Skip to content

Commit

Permalink
feat: impl Eval and Binder traits
Browse files Browse the repository at this point in the history
*Binder*: this trait is for generically
handling the encoding and decoding of
Var and Lambda.parameter.

*Eval*: this trait is for generically
looking up Var in Env

Eval is implemented on DeBruijn but not
for Name because Name is not evaluatable
there is no way to look it up in the environment.

All Name, NamedDeBruijn, and DeBruijn implement
Binder because they are all technically encodable.

**Note**: only DeBruijn actually ever goes on chain.
  • Loading branch information
rvcas committed Dec 2, 2024
1 parent c927c02 commit 0d96bb1
Show file tree
Hide file tree
Showing 27 changed files with 620 additions and 365 deletions.
66 changes: 35 additions & 31 deletions crates/uplc/benches/benchmarks/fibonacci.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use bumpalo::Bump;
use criterion::{criterion_group, Criterion};

use uplc::term::Term;
use uplc::{binder::DeBruijn, term::Term};

use super::utils;

Expand All @@ -10,65 +10,65 @@ pub fn run(c: &mut Criterion) {
b.iter_with_setup(
|| {
utils::setup_term(|arena: &Bump| {
let double_force = Term::var(arena, 1)
.apply(arena, Term::var(arena, 1))
.lambda(arena, 0)
let double_force = Term::var(arena, DeBruijn::new(arena, 1))
.apply(arena, Term::var(arena, DeBruijn::new(arena, 1)))
.lambda(arena, DeBruijn::zero(arena))
.delay(arena)
.force(arena)
.apply(
arena,
Term::var(arena, 3)
Term::var(arena, DeBruijn::new(arena, 3))
.apply(
arena,
Term::var(arena, 1)
.apply(arena, Term::var(arena, 1))
.lambda(arena, 0)
Term::var(arena, DeBruijn::new(arena, 1))
.apply(arena, Term::var(arena, DeBruijn::new(arena, 1)))
.lambda(arena, DeBruijn::zero(arena))
.delay(arena)
.force(arena)
.apply(arena, Term::var(arena, 2)),
.apply(arena, Term::var(arena, DeBruijn::new(arena, 2))),
)
.apply(arena, Term::var(arena, 1))
.lambda(arena, 0)
.lambda(arena, 0),
.apply(arena, Term::var(arena, DeBruijn::new(arena, 1)))
.lambda(arena, DeBruijn::zero(arena))
.lambda(arena, DeBruijn::zero(arena)),
)
.lambda(arena, 0)
.lambda(arena, DeBruijn::zero(arena))
.delay(arena)
.delay(arena)
.force(arena)
.force(arena);

let if_condition = Term::if_then_else(arena)
.force(arena)
.apply(arena, Term::var(arena, 3))
.apply(arena, Term::var(arena, 2))
.apply(arena, Term::var(arena, 1))
.apply(arena, Term::var(arena, DeBruijn::new(arena, 3)))
.apply(arena, Term::var(arena, DeBruijn::new(arena, 2)))
.apply(arena, Term::var(arena, DeBruijn::new(arena, 1)))
.apply(arena, Term::unit(arena))
.lambda(arena, 0)
.lambda(arena, 0)
.lambda(arena, 0)
.lambda(arena, DeBruijn::zero(arena))
.lambda(arena, DeBruijn::zero(arena))
.lambda(arena, DeBruijn::zero(arena))
.delay(arena)
.force(arena);

let add = Term::add_integer(arena)
.apply(
arena,
Term::var(arena, 3).apply(
Term::var(arena, DeBruijn::new(arena, 3)).apply(
arena,
Term::subtract_integer(arena)
.apply(arena, Term::var(arena, 2))
.apply(arena, Term::var(arena, DeBruijn::new(arena, 2)))
.apply(arena, Term::integer_from(arena, 1)),
),
)
.apply(
arena,
Term::var(arena, 3).apply(
Term::var(arena, DeBruijn::new(arena, 3)).apply(
arena,
Term::subtract_integer(arena)
.apply(arena, Term::var(arena, 2))
.apply(arena, Term::var(arena, DeBruijn::new(arena, 2)))
.apply(arena, Term::integer_from(arena, 2)),
),
)
.lambda(arena, 0);
.lambda(arena, DeBruijn::zero(arena));

double_force
.apply(
Expand All @@ -77,17 +77,21 @@ pub fn run(c: &mut Criterion) {
.apply(
arena,
Term::less_than_equals_integer(arena)
.apply(arena, Term::var(arena, 1))
.apply(arena, Term::var(arena, DeBruijn::new(arena, 1)))
.apply(arena, Term::integer_from(arena, 1)),
)
.apply(arena, Term::var(arena, 2).lambda(arena, 0))
.apply(
arena,
Term::var(arena, DeBruijn::new(arena, 2))
.lambda(arena, DeBruijn::zero(arena)),
)
.apply(arena, add)
.lambda(arena, 0)
.lambda(arena, 0),
.lambda(arena, DeBruijn::zero(arena))
.lambda(arena, DeBruijn::zero(arena)),
)
.apply(arena, Term::var(arena, 1))
.lambda(arena, 0)
.apply(arena, Term::integer_from(arena, 20))
.apply(arena, Term::var(arena, DeBruijn::new(arena, 1)))
.lambda(arena, DeBruijn::zero(arena))
.apply(arena, Term::integer_from(arena, 15))
})
},
// Benchmark: only the eval call
Expand Down
4 changes: 3 additions & 1 deletion crates/uplc/benches/benchmarks/haskell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::{fs, time::Duration};
use bumpalo::Bump;
use criterion::{criterion_group, Criterion};
use itertools::Itertools;
use uplc::{binder::DeBruijn, flat};

pub fn run(c: &mut Criterion) {
let data_dir = std::path::Path::new("benches/benchmarks/data");
Expand All @@ -27,7 +28,8 @@ pub fn run(c: &mut Criterion) {

c.bench_function(&file_name, |b| {
b.iter(|| {
let program = uplc::flat::decode(&arena, &script).expect("Failed to decode");
let program =
flat::decode::<DeBruijn>(&arena, &script).expect("Failed to decode");

let result = program.eval(&arena);

Expand Down
7 changes: 4 additions & 3 deletions crates/uplc/benches/benchmarks/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use bumpalo::Bump;
use ouroboros::self_referencing;

use uplc::{
binder::DeBruijn,
program::{Program, Version},
term::Term,
};
Expand All @@ -11,7 +12,7 @@ pub struct BenchState {
pub arena: Bump,
#[borrows(arena)]
#[covariant]
pub program: &'this Program<'this>,
pub program: &'this Program<'this, DeBruijn>,
}

impl BenchState {
Expand All @@ -27,7 +28,7 @@ impl BenchState {

pub fn setup_program<F>(program_builder: F) -> BenchState
where
F: for<'this> FnOnce(&'this Bump) -> &'this Program<'this>,
F: for<'this> FnOnce(&'this Bump) -> &'this Program<'this, DeBruijn>,
{
let arena = Bump::new();

Expand All @@ -42,7 +43,7 @@ where
#[inline]
pub fn setup_term<F>(term_builder: F) -> BenchState
where
F: for<'this> FnOnce(&'this Bump) -> &'this Term<'this>,
F: for<'this> FnOnce(&'this Bump) -> &'this Term<'this, DeBruijn>,
{
setup_program(|arena| {
let term = term_builder(arena);
Expand Down
57 changes: 57 additions & 0 deletions crates/uplc/src/binder/debruijn.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use bumpalo::Bump;

use super::{Binder, Eval};

#[derive(Debug, Eq, PartialEq)]
pub struct DeBruijn(usize);

impl DeBruijn {
pub fn new<'a>(arena: &'a Bump, i: usize) -> &'a Self {
arena.alloc(DeBruijn(i))
}

pub fn zero<'a>(arena: &'a Bump) -> &'a Self {
arena.alloc(DeBruijn(0))
}
}

impl Binder for DeBruijn {
fn var_encode(&self, e: &mut crate::flat::Encoder) -> Result<(), crate::flat::FlatEncodeError> {
e.word(self.0);

Ok(())
}

fn var_decode<'a>(
arena: &'a bumpalo::Bump,
d: &mut crate::flat::Decoder,
) -> Result<&'a Self, crate::flat::FlatDecodeError> {
let i = d.word()?;

let d = DeBruijn::new(arena, i);

Ok(d)
}

fn parameter_encode(
&self,
_e: &mut crate::flat::Encoder,
) -> Result<(), crate::flat::FlatEncodeError> {
Ok(())
}

fn parameter_decode<'a>(
arena: &'a bumpalo::Bump,
_d: &mut crate::flat::Decoder,
) -> Result<&'a Self, crate::flat::FlatDecodeError> {
let d = DeBruijn::new(arena, 0);

Ok(d)
}
}

impl Eval for DeBruijn {
fn index(&self) -> usize {
self.0
}
}
31 changes: 31 additions & 0 deletions crates/uplc/src/binder/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use bumpalo::Bump;

mod debruijn;
mod name;
mod named_debruijn;

pub use debruijn::*;
pub use name::*;
pub use named_debruijn::*;

use crate::flat;

pub trait Binder: std::fmt::Debug {
// this might not need to return a Result
fn var_encode(&self, e: &mut flat::Encoder) -> Result<(), flat::FlatEncodeError>;
fn var_decode<'a>(
arena: &'a Bump,
d: &mut flat::Decoder,
) -> Result<&'a Self, flat::FlatDecodeError>;

// this might not need to return a Result
fn parameter_encode(&self, e: &mut flat::Encoder) -> Result<(), flat::FlatEncodeError>;
fn parameter_decode<'a>(
arena: &'a Bump,
d: &mut flat::Decoder,
) -> Result<&'a Self, flat::FlatDecodeError>;
}

pub trait Eval: Binder {
fn index(&self) -> usize;
}
File renamed without changes.
Empty file.
7 changes: 5 additions & 2 deletions crates/uplc/src/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use bumpalo::{
Bump,
};

use crate::{data::PlutusData, machine::MachineError, typ::Type};
use crate::{binder::Eval, data::PlutusData, machine::MachineError, typ::Type};

#[derive(Debug, PartialEq)]
pub enum Constant<'a> {
Expand Down Expand Up @@ -99,7 +99,10 @@ impl<'a> Constant<'a> {
arena.alloc(Constant::Bls12_381MlResult(ml_res))
}

pub fn unwrap_data(&'a self) -> Result<&'a PlutusData<'a>, MachineError<'a>> {
pub fn unwrap_data<V>(&'a self) -> Result<&'a PlutusData<'a>, MachineError<'a, V>>
where
V: Eval,
{
match self {
Constant::Data(data) => Ok(data),
_ => Err(MachineError::not_data(self)),
Expand Down
30 changes: 23 additions & 7 deletions crates/uplc/src/data.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use bumpalo::{collections::Vec as BumpVec, Bump};

use crate::{
binder::Eval,
constant::{integer_from, Constant, Integer},
flat::Ctx,
machine::MachineError,
Expand Down Expand Up @@ -57,39 +58,54 @@ impl<'a> PlutusData<'a> {
minicbor::decode_with(cbor, &mut Ctx { arena })
}

pub fn unwrap_constr(
pub fn unwrap_constr<V>(
&'a self,
) -> Result<(&'a u64, &'a BumpVec<&'a PlutusData<'a>>), MachineError<'a>> {
) -> Result<(&'a u64, &'a BumpVec<&'a PlutusData<'a>>), MachineError<'a, V>>
where
V: Eval,
{
match self {
PlutusData::Constr { tag, fields } => Ok((tag, fields)),
_ => Err(MachineError::malformed_data(self)),
}
}

pub fn unwrap_map(
pub fn unwrap_map<V>(
&'a self,
) -> Result<&'a BumpVec<(&'a PlutusData<'a>, &'a PlutusData<'a>)>, MachineError<'a>> {
) -> Result<&'a BumpVec<(&'a PlutusData<'a>, &'a PlutusData<'a>)>, MachineError<'a, V>>
where
V: Eval,
{
match self {
PlutusData::Map(fields) => Ok(fields),
_ => Err(MachineError::malformed_data(self)),
}
}

pub fn unwrap_integer(&'a self) -> Result<&'a Integer, MachineError<'a>> {
pub fn unwrap_integer<V>(&'a self) -> Result<&'a Integer, MachineError<'a, V>>
where
V: Eval,
{
match self {
PlutusData::Integer(i) => Ok(i),
_ => Err(MachineError::malformed_data(self)),
}
}

pub fn unwrap_byte_string(&'a self) -> Result<&'a BumpVec<u8>, MachineError<'a>> {
pub fn unwrap_byte_string<V>(&'a self) -> Result<&'a BumpVec<u8>, MachineError<'a, V>>
where
V: Eval,
{
match self {
PlutusData::ByteString(bytes) => Ok(bytes),
_ => Err(MachineError::malformed_data(self)),
}
}

pub fn unwrap_list(&'a self) -> Result<&'a BumpVec<&'a PlutusData<'a>>, MachineError<'a>> {
pub fn unwrap_list<V>(&'a self) -> Result<&'a BumpVec<&'a PlutusData<'a>>, MachineError<'a, V>>
where
V: Eval,
{
match self {
PlutusData::List(items) => Ok(items),
_ => Err(MachineError::malformed_data(self)),
Expand Down
Loading

0 comments on commit 0d96bb1

Please sign in to comment.