use crate::tir::TIROp;
#[derive(Debug, Clone, PartialEq)]
pub enum Noun {
Atom(u64),
Cell(Box<Noun>, Box<Noun>),
}
impl Noun {
pub fn atom(value: u64) -> Self {
Noun::Atom(value)
}
pub fn cell(head: Noun, tail: Noun) -> Self {
Noun::Cell(Box::new(head), Box::new(tail))
}
pub fn slot(axis: u64) -> Self {
Noun::cell(Noun::atom(0), Noun::atom(axis))
}
pub fn constant(value: Noun) -> Self {
Noun::cell(Noun::atom(1), value)
}
pub fn evaluate(subject: Noun, formula: Noun) -> Self {
Noun::cell(Noun::atom(2), Noun::cell(subject, formula))
}
pub fn cell_test(noun: Noun) -> Self {
Noun::cell(Noun::atom(3), noun)
}
pub fn increment(noun: Noun) -> Self {
Noun::cell(Noun::atom(4), noun)
}
pub fn equals(a: Noun, b: Noun) -> Self {
Noun::cell(Noun::atom(5), Noun::cell(a, b))
}
pub fn branch(test: Noun, yes: Noun, no: Noun) -> Self {
Noun::cell(Noun::atom(6), Noun::cell(test, Noun::cell(yes, no)))
}
pub fn compose(a: Noun, b: Noun) -> Self {
Noun::cell(Noun::atom(7), Noun::cell(a, b))
}
pub fn push(a: Noun, b: Noun) -> Self {
Noun::cell(Noun::atom(8), Noun::cell(a, b))
}
pub fn invoke(axis: u64, core: Noun) -> Self {
Noun::cell(Noun::atom(9), Noun::cell(Noun::atom(axis), core))
}
pub fn edit(axis: u64, value: Noun, target: Noun) -> Self {
Noun::cell(
Noun::atom(10),
Noun::cell(Noun::cell(Noun::atom(axis), value), target),
)
}
pub fn hint(hint: Noun, formula: Noun) -> Self {
Noun::cell(Noun::atom(11), Noun::cell(hint, formula))
}
}
impl std::fmt::Display for Noun {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Noun::Atom(v) => write!(f, "{}", v),
Noun::Cell(h, t) => write!(f, "[{} {}]", h, t),
}
}
}
pub trait TreeLowering {
fn target_name(&self) -> &str;
fn lower(&self, ops: &[TIROp]) -> Noun;
fn serialize(&self, noun: &Noun) -> Vec<u8>;
}
pub fn create_tree_lowering(_target: &str) -> Option<Box<dyn TreeLowering>> {
None
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_noun_display() {
assert_eq!(format!("{}", Noun::atom(42)), "42");
assert_eq!(
format!("{}", Noun::cell(Noun::atom(1), Noun::atom(2))),
"[1 2]"
);
assert_eq!(format!("{}", Noun::slot(7)), "[0 7]");
assert_eq!(format!("{}", Noun::constant(Noun::atom(42))), "[1 42]");
}
#[test]
fn test_noun_formulas() {
let formula = Noun::branch(
Noun::slot(2),
Noun::constant(Noun::atom(1)),
Noun::constant(Noun::atom(0)),
);
assert_eq!(format!("{}", formula), "[6 [[0 2] [[1 1] [1 0]]]]");
}
#[test]
fn test_noun_compose() {
let formula = Noun::compose(
Noun::constant(Noun::atom(42)),
Noun::increment(Noun::slot(1)),
);
assert_eq!(format!("{}", formula), "[7 [[1 42] [4 [0 1]]]]");
}
#[test]
fn test_create_tree_lowering() {
assert!(create_tree_lowering("nock").is_none());
assert!(create_tree_lowering("triton").is_none());
}
}