a4-core 0.0.4

A forth-inspired, bytecode-compiled scripting language for Anachro Powerbus
Documentation
use crate::*;
use core::fmt::Write;

pub fn bi_emit<BuiltinTok, SeqTok, Sdata, Sexec, O>(
    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
) -> Result<(), Error>
where
    Sdata: Stack<Item = i32>,
    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
    SeqTok: Clone,
    BuiltinTok: Clone,
    O: Write,
{
    let word = ctxt.data_stk.pop()? as u32;
    let symbol = core::char::from_u32(word).unwrap_or('');
    write!(&mut ctxt.cur_output, "{}", symbol).map_err(|_| Error::OutputFormat)
}

pub fn bi_pop<BuiltinTok, SeqTok, Sdata, Sexec, O>(
    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
) -> Result<(), Error>
where
    Sdata: Stack<Item = i32>,
    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
    SeqTok: Clone,
    BuiltinTok: Clone,
    O: Write,
{
    writeln!(&mut ctxt.cur_output, "{}", ctxt.data_stk.pop()?)?;
    Ok(())
}

pub fn bi_drop<BuiltinTok, SeqTok, Sdata, Sexec, O>(
    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
) -> Result<(), Error>
where
    Sdata: Stack<Item = i32>,
    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
    SeqTok: Clone,
    BuiltinTok: Clone,
    O: Write,
{
    let _ = ctxt.data_stk.pop()?;
    Ok(())
}

pub fn bi_rot<BuiltinTok, SeqTok, Sdata, Sexec, O>(
    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
) -> Result<(), Error>
where
    Sdata: Stack<Item = i32>,
    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
    SeqTok: Clone,
    BuiltinTok: Clone,
    O: Write,
{
    let top = ctxt.data_stk.pop()?;
    let mid = ctxt.data_stk.pop()?;
    let bot = ctxt.data_stk.pop()?;

    ctxt.data_stk.push(mid)?;
    ctxt.data_stk.push(top)?;
    ctxt.data_stk.push(bot)?;

    Ok(())
}

pub fn bi_cr<BuiltinTok, SeqTok, Sdata, Sexec, O>(
    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
) -> Result<(), Error>
where
    Sdata: Stack<Item = i32>,
    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
    SeqTok: Clone,
    BuiltinTok: Clone,
    O: Write,
{
    writeln!(&mut ctxt.cur_output)?;
    Ok(())
}

pub fn bi_lt<BuiltinTok, SeqTok, Sdata, Sexec, O>(
    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
) -> Result<(), Error>
where
    Sdata: Stack<Item = i32>,
    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
    SeqTok: Clone,
    BuiltinTok: Clone,
    O: Write,
{
    let val2 = ctxt.data_stk.pop()?;
    let val1 = ctxt.data_stk.pop()?;
    ctxt.data_stk.push(if val1 < val2 { -1 } else { 0 })?;
    Ok(())
}

pub fn bi_gt<BuiltinTok, SeqTok, Sdata, Sexec, O>(
    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
) -> Result<(), Error>
where
    Sdata: Stack<Item = i32>,
    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
    SeqTok: Clone,
    BuiltinTok: Clone,
    O: Write,
{
    let val2 = ctxt.data_stk.pop()?;
    let val1 = ctxt.data_stk.pop()?;
    ctxt.data_stk.push(if val1 > val2 { -1 } else { 0 })?;
    Ok(())
}

pub fn bi_retstk_push<BuiltinTok, SeqTok, Sdata, Sexec, O>(
    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
) -> Result<(), Error>
where
    Sdata: Stack<Item = i32>,
    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
    SeqTok: Clone,
    BuiltinTok: Clone,
    O: Write,
{
    let val = ctxt.data_stk.pop()?;
    ctxt.ret_stk.push(val)?;
    Ok(())
}

pub fn bi_retstk_pop<BuiltinTok, SeqTok, Sdata, Sexec, O>(
    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
) -> Result<(), Error>
where
    Sdata: Stack<Item = i32>,
    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
    SeqTok: Clone,
    BuiltinTok: Clone,
    O: Write,
{
    let val = ctxt.ret_stk.pop()?;
    ctxt.data_stk.push(val)?;
    Ok(())
}

pub fn bi_eq<BuiltinTok, SeqTok, Sdata, Sexec, O>(
    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
) -> Result<(), Error>
where
    Sdata: Stack<Item = i32>,
    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
    SeqTok: Clone,
    BuiltinTok: Clone,
    O: Write,
{
    let val1 = ctxt.data_stk.pop()?;
    let val2 = ctxt.data_stk.pop()?;
    ctxt.data_stk.push(if val1 == val2 { -1 } else { 0 })?;
    Ok(())
}

pub fn bi_add<BuiltinTok, SeqTok, Sdata, Sexec, O>(
    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
) -> Result<(), Error>
where
    Sdata: Stack<Item = i32>,
    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
    SeqTok: Clone,
    BuiltinTok: Clone,
    O: Write,
{
    let val1 = ctxt.data_stk.pop()?;
    let val2 = ctxt.data_stk.pop()?;
    ctxt.data_stk.push(val1.wrapping_add(val2))?;
    Ok(())
}

pub fn bi_dup<BuiltinTok, SeqTok, Sdata, Sexec, O>(
    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
) -> Result<(), Error>
where
    Sdata: Stack<Item = i32>,
    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
    SeqTok: Clone,
    BuiltinTok: Clone,
    O: Write,
{
    let val1 = *ctxt.data_stk.last()?;
    ctxt.data_stk.push(val1)?;
    Ok(())
}

pub fn bi_retstk_dup<BuiltinTok, SeqTok, Sdata, Sexec, O>(
    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
) -> Result<(), Error>
where
    Sdata: Stack<Item = i32>,
    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
    SeqTok: Clone,
    BuiltinTok: Clone,
    O: Write,
{
    let val1 = *ctxt.ret_stk.last()?;
    ctxt.ret_stk.push(val1)?;
    Ok(())
}

pub fn bi_2dup<BuiltinTok, SeqTok, Sdata, Sexec, O>(
    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
) -> Result<(), Error>
where
    Sdata: Stack<Item = i32>,
    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
    SeqTok: Clone,
    BuiltinTok: Clone,
    O: Write,
{
    let val1 = ctxt.data_stk.pop()?;
    let val2 = ctxt.data_stk.pop()?;
    ctxt.data_stk.push(val2)?;
    ctxt.data_stk.push(val1)?;
    ctxt.data_stk.push(val2)?;
    ctxt.data_stk.push(val1)?;
    Ok(())
}

pub fn bi_retstk_swap<BuiltinTok, SeqTok, Sdata, Sexec, O>(
    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
) -> Result<(), Error>
where
    Sdata: Stack<Item = i32>,
    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
    SeqTok: Clone,
    BuiltinTok: Clone,
    O: Write,
{
    let top = ctxt.ret_stk.pop()?;
    let bot = ctxt.ret_stk.pop()?;
    ctxt.ret_stk.push(top)?;
    ctxt.ret_stk.push(bot)?;

    Ok(())
}

pub fn bi_swap<BuiltinTok, SeqTok, Sdata, Sexec, O>(
    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
) -> Result<(), Error>
where
    Sdata: Stack<Item = i32>,
    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
    SeqTok: Clone,
    BuiltinTok: Clone,
    O: Write,
{
    let top = ctxt.data_stk.pop()?;
    let bot = ctxt.data_stk.pop()?;
    ctxt.data_stk.push(top)?;
    ctxt.data_stk.push(bot)?;

    Ok(())
}

pub fn bi_pick<BuiltinTok, SeqTok, Sdata, Sexec, O>(
    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
) -> Result<(), Error>
where
    Sdata: Stack<Item = i32>,
    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
    SeqTok: Clone,
    BuiltinTok: Clone,
    O: Write,
{
    let top = ctxt.data_stk.pop()?;
    let val = *ctxt.data_stk.peek_back(top.try_into().map_err(|_| Error::DataStackUnderflow)?)?;
    ctxt.data_stk.push(val)?;

    Ok(())
}

pub fn bi_roll<BuiltinTok, SeqTok, Sdata, Sexec, O>(
    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
) -> Result<(), Error>
where
    Sdata: Stack<Item = i32>,
    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
    SeqTok: Clone,
    BuiltinTok: Clone,
    O: Write,
{
    let top = ctxt.data_stk.pop()?;
    let val = ctxt.data_stk.pop_back(top.try_into().map_err(|_| Error::DataStackUnderflow)?)?;
    ctxt.data_stk.push(val)?;

    Ok(())
}

pub fn bi_priv_loop<BuiltinTok, SeqTok, Sdata, Sexec, O>(
    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
) -> Result<(), Error>
where
    Sdata: Stack<Item = i32>,
    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
    SeqTok: Clone,
    BuiltinTok: Clone,
    O: Write,
{
    let lmt = ctxt.ret_stk.pop()?;
    let mut idx = ctxt.ret_stk.pop()?;

    idx = idx.checked_add(1).ok_or(Error::BadMath)?;

    if idx == lmt {
        ctxt.data_stk.push(-1)?;
    } else {
        ctxt.data_stk.push(0)?;
        ctxt.ret_stk.push(idx)?;
        ctxt.ret_stk.push(lmt)?;
    }

    Ok(())
}