// ---
// tags: nox, rust
// crystal-type: source
// crystal-domain: comp
// ---
//! reduce โ dispatch + budget metering + shared helpers
//! pattern implementations live in patterns/
use nebu::Goldilocks;
use crate::noun::{Order, NounId, Noun, Tag};
use crate::call::CallProvider;
use crate::patterns;
#[derive(Debug)]
pub enum Outcome {
Ok(NounId, u64),
Halt(u64),
Error(ErrorKind),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ErrorKind {
TypeError,
AxisError,
InvZero,
Unavailable,
Malformed,
CallRejected,
}
fn cost(tag: u64) -> u64 {
match tag { 8 => 64, 15 => 300, _ => 1 }
}
pub fn reduce<const N: usize>(
order: &mut Order<N>, object: NounId, formula: NounId, budget: u64, hints: &dyn CallProvider<N>,
) -> Outcome {
let (tag_ref, body) = match order.get(formula).inner {
Noun::Cell { left, right } => (left, right),
Noun::Atom { .. } => return Outcome::Error(ErrorKind::Malformed),
};
let tag = match order.atom_value(tag_ref) {
Some((v, _)) => v.as_u64(),
None => return Outcome::Error(ErrorKind::Malformed),
};
let c = cost(tag);
if budget < c { return Outcome::Halt(budget); }
let budget = budget - c;
match tag {
0 => patterns::axis::axis(order, object, body, budget),
1 => patterns::quote::quote(body, budget),
2 => patterns::compose::compose(order, object, body, budget, hints),
3 => patterns::cons::cons(order, object, body, budget, hints),
4 => patterns::branch::branch(order, object, body, budget, hints),
5 => patterns::add::add(order, object, body, budget, hints),
6 => patterns::sub::sub(order, object, body, budget, hints),
7 => patterns::mul::mul(order, object, body, budget, hints),
8 => patterns::inv::inv(order, object, body, budget, hints),
9 => patterns::eq::eq(order, object, body, budget, hints),
10 => patterns::lt::lt(order, object, body, budget, hints),
11 => patterns::xor::xor(order, object, body, budget, hints),
12 => patterns::and::and(order, object, body, budget, hints),
13 => patterns::not::not(order, object, body, budget, hints),
14 => patterns::shl::shl(order, object, body, budget, hints),
15 => patterns::hash::hash(order, object, body, budget, hints),
16 => patterns::call::call_witness(order, object, body, budget, hints),
17 => patterns::look::look(order, object, body, budget, hints),
_ => Outcome::Error(ErrorKind::Malformed),
}
}
// === public helpers used by pattern implementations ===
pub fn cell_pair<const N: usize>(order: &Order<N>, r: NounId) -> Option<(NounId, NounId)> {
match order.get(r).inner {
Noun::Cell { left, right } => Some((left, right)),
_ => None,
}
}
pub fn evaluate<const N: usize>(
order: &mut Order<N>, object: NounId, formula: NounId, budget: u64, hints: &dyn CallProvider<N>,
) -> core::result::Result<(NounId, u64), Outcome> {
match reduce(order, object, formula, budget, hints) {
Outcome::Ok(r, b) => Ok((r, b)),
other => Err(other),
}
}
pub fn evaluate_field<const N: usize>(
order: &mut Order<N>, object: NounId, formula: NounId, budget: u64, hints: &dyn CallProvider<N>,
) -> core::result::Result<(Goldilocks, u64), Outcome> {
let (result, budget) = evaluate(order, object, formula, budget, hints)?;
match order.atom_value(result) {
Some((v, Tag::Field)) | Some((v, Tag::Word)) => Ok((v, budget)),
_ => Err(Outcome::Error(ErrorKind::TypeError)),
}
}
pub fn evaluate_word<const N: usize>(
order: &mut Order<N>, object: NounId, formula: NounId, budget: u64, hints: &dyn CallProvider<N>,
) -> core::result::Result<(u64, u64), Outcome> {
let (result, budget) = evaluate(order, object, formula, budget, hints)?;
match order.atom_value(result) {
Some((v, Tag::Word)) => Ok((v.as_u64(), budget)),
Some((v, Tag::Field)) if v.as_u64() < (1u64 << 32) => Ok((v.as_u64(), budget)),
_ => Err(Outcome::Error(ErrorKind::TypeError)),
}
}
pub fn make_field<const N: usize>(order: &mut Order<N>, v: Goldilocks, budget: u64) -> Outcome {
match order.atom(v, Tag::Field) { Some(r) => Outcome::Ok(r, budget), None => Outcome::Error(ErrorKind::Unavailable) }
}
pub fn make_word<const N: usize>(order: &mut Order<N>, v: u64, budget: u64) -> Outcome {
match order.atom(Goldilocks::new(v & 0xFFFF_FFFF), Tag::Word) { Some(r) => Outcome::Ok(r, budget), None => Outcome::Error(ErrorKind::Unavailable) }
}
pub fn field_binary_op<const N: usize>(
order: &mut Order<N>, object: NounId, body: NounId, budget: u64, hints: &dyn CallProvider<N>,
op: fn(Goldilocks, Goldilocks) -> Goldilocks,
) -> Outcome {
let (a, b) = match cell_pair(order, body) { Some(p) => p, None => return Outcome::Error(ErrorKind::Malformed) };
let (va, budget) = match evaluate_field(order, object, a, budget, hints) { Ok(v) => v, Err(o) => return o };
let (vb, budget) = match evaluate_field(order, object, b, budget, hints) { Ok(v) => v, Err(o) => return o };
make_field(order, op(va, vb), budget)
}
pub fn word_binary_op<const N: usize>(
order: &mut Order<N>, object: NounId, body: NounId, budget: u64, hints: &dyn CallProvider<N>,
op: fn(u64, u64) -> u64,
) -> Outcome {
let (a, b) = match cell_pair(order, body) { Some(p) => p, None => return Outcome::Error(ErrorKind::Malformed) };
let (va, budget) = match evaluate_word(order, object, a, budget, hints) { Ok(v) => v, Err(o) => return o };
let (vb, budget) = match evaluate_word(order, object, b, budget, hints) { Ok(v) => v, Err(o) => return o };
make_word(order, op(va, vb), budget)
}
nox/rs/reduce.rs
ฯ 0.0%
// ---
// tags: nox, rust
// crystal-type: source
// crystal-domain: comp
// ---
//! reduce โ dispatch + budget metering + shared helpers
//! pattern implementations live in patterns/
use Goldilocks;
use crate;
use crateCallProvider;
use cratepatterns;
// === public helpers used by pattern implementations ===