diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 8b36f337..47bdd860 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -1,5 +1,5 @@ use uplc::{ - ast::{NamedDeBruijn, Program}, + ast::{DeBruijn, NamedDeBruijn, Program}, parser, }; @@ -12,11 +12,12 @@ fn main() -> anyhow::Result<()> { let program = parser::program(&code)?; + println!("\nName:"); println!("{:#?}", program); let flat_bytes = program.to_flat()?; - print!("flat bits: "); + print!("\nflat bits:\n"); for byte in flat_bytes { print!("{:08b} ", byte); @@ -24,9 +25,35 @@ fn main() -> anyhow::Result<()> { println!(); - let program: Program = program.try_into().unwrap(); + let program_nd: Program = program.try_into().unwrap(); - println!("{:#?}", program); + println!("\nNamed De Bruijn:"); + println!("{:#?}", program_nd); + + let flat_bytes = program_nd.to_flat()?; + + print!("\nflat bits:\n"); + + for byte in flat_bytes { + print!("{:08b} ", byte); + } + + println!(); + + let program_d: Program = program_nd.into(); + + println!("\nDe Bruijn:"); + println!("{:#?}", program_d); + + let flat_bytes = program_d.to_flat()?; + + print!("\nflat bits:\n"); + + for byte in flat_bytes { + print!("{:08b} ", byte); + } + + println!(); Ok(()) } diff --git a/crates/uplc/example/integer.uplc b/crates/uplc/example/integer.uplc index 86df1598..6ac9f3c9 100644 --- a/crates/uplc/example/integer.uplc +++ b/crates/uplc/example/integer.uplc @@ -1,3 +1,3 @@ (program 11.22.33 - (lam x (lam x y)) + (lam x (lam x x)) ) \ No newline at end of file diff --git a/crates/uplc/src/ast.rs b/crates/uplc/src/ast.rs index f0f37663..ea766a6f 100644 --- a/crates/uplc/src/ast.rs +++ b/crates/uplc/src/ast.rs @@ -88,6 +88,12 @@ pub struct NamedDeBruijn { #[derive(Debug, Clone, PartialEq, Copy)] pub struct DeBruijn(usize); +impl DeBruijn { + pub fn new(index: usize) -> Self { + DeBruijn(index) + } +} + impl From for DeBruijn { fn from(i: usize) -> Self { DeBruijn(i) @@ -126,17 +132,6 @@ impl TryFrom> for Program { } } -impl TryFrom> for Program { - type Error = String; - - fn try_from(value: Program) -> Result { - Ok(Program:: { - version: value.version, - term: value.term.try_into()?, - }) - } -} - impl TryFrom> for Term { type Error = String; @@ -153,6 +148,42 @@ impl TryFrom> for Term { } } +impl TryFrom> for Program { + type Error = String; + + fn try_from(value: Program) -> Result { + Ok(Program:: { + version: value.version, + term: value.term.try_into()?, + }) + } +} + +impl TryFrom> for Term { + type Error = String; + + fn try_from(value: Term) -> Result as TryFrom>>::Error> { + let mut converter = Converter::new(); + + let term = converter + .name_to_debruijn(value) + .map_err(|err| err.to_string())?; + + Ok(term) + } +} + +impl TryFrom> for Program { + type Error = String; + + fn try_from(value: Program) -> Result { + Ok(Program:: { + version: value.version, + term: value.term.try_into()?, + }) + } +} + impl TryFrom> for Term { type Error = String; @@ -168,3 +199,64 @@ impl TryFrom> for Term { Ok(term) } } + +impl From> for Program { + fn from(value: Program) -> Self { + Program:: { + version: value.version, + term: value.term.into(), + } + } +} + +impl From> for Term { + fn from(value: Term) -> Self { + let mut converter = Converter::new(); + + converter.named_debruijn_to_debruijn(value) + } +} + +impl TryFrom> for Program { + type Error = String; + + fn try_from(value: Program) -> Result { + Ok(Program:: { + version: value.version, + term: value.term.try_into()?, + }) + } +} + +impl TryFrom> for Term { + type Error = String; + + fn try_from( + value: Term, + ) -> Result as TryFrom>>::Error> { + let mut converter = Converter::new(); + + let term = converter + .debruijn_to_name(value) + .map_err(|err| err.to_string())?; + + Ok(term) + } +} + +impl From> for Program { + fn from(value: Program) -> Self { + Program:: { + version: value.version, + term: value.term.into(), + } + } +} + +impl From> for Term { + fn from(value: Term) -> Self { + let mut converter = Converter::new(); + + converter.debruijn_to_named_debruijn(value) + } +} diff --git a/crates/uplc/src/debruijn.rs b/crates/uplc/src/debruijn.rs index 624525e9..047e4608 100644 --- a/crates/uplc/src/debruijn.rs +++ b/crates/uplc/src/debruijn.rs @@ -5,20 +5,20 @@ use crate::ast::{DeBruijn, Name, NamedDeBruijn, Term, Unique}; #[derive(Debug, Copy, Clone)] struct Level(usize); -pub(crate) struct Converter { +pub struct Converter { current_level: Level, levels: Vec>, } impl Converter { - pub(crate) fn new() -> Self { + pub fn new() -> Self { Converter { current_level: Level(0), levels: vec![HashMap::new()], } } - pub(crate) fn name_to_named_debruijn( + pub fn name_to_named_debruijn( &mut self, term: Term, ) -> anyhow::Result> { @@ -65,13 +65,97 @@ impl Converter { Ok(converted_term) } - pub(crate) fn named_debruijn_to_name( + pub fn name_to_debruijn(&mut self, term: Term) -> anyhow::Result> { + let converted_term = match term { + Term::Var(Name { unique, .. }) => Term::Var(self.get_index(unique)?), + Term::Delay(term) => Term::Delay(Box::new(self.name_to_debruijn(*term)?)), + Term::Lambda { + parameter_name, + body, + } => { + self.declare_unique(parameter_name.unique); + + let name = self.get_index(parameter_name.unique)?; + + self.start_scope(); + + let body = self.name_to_debruijn(*body)?; + + self.end_scope(); + + Term::Lambda { + parameter_name: name, + body: Box::new(body), + } + } + Term::Apply { function, argument } => Term::Apply { + function: Box::new(self.name_to_debruijn(*function)?), + argument: Box::new(self.name_to_debruijn(*argument)?), + }, + Term::Constant(constant) => Term::Constant(constant), + Term::Force(term) => Term::Force(Box::new(self.name_to_debruijn(*term)?)), + Term::Error => Term::Error, + Term::Builtin(builtin) => Term::Builtin(builtin), + }; + + Ok(converted_term) + } + + pub fn named_debruijn_to_name( &mut self, _term: Term, ) -> anyhow::Result> { todo!() } + pub fn named_debruijn_to_debruijn(&mut self, term: Term) -> Term { + match term { + Term::Var(name) => Term::Var(name.into()), + Term::Delay(term) => Term::Delay(Box::new(self.named_debruijn_to_debruijn(*term))), + Term::Lambda { + parameter_name, + body, + } => Term::Lambda { + parameter_name: parameter_name.into(), + body: Box::new(self.named_debruijn_to_debruijn(*body)), + }, + Term::Apply { function, argument } => Term::Apply { + function: Box::new(self.named_debruijn_to_debruijn(*function)), + argument: Box::new(self.named_debruijn_to_debruijn(*argument)), + }, + Term::Constant(constant) => Term::Constant(constant), + Term::Force(term) => Term::Force(Box::new(self.named_debruijn_to_debruijn(*term))), + Term::Error => Term::Error, + Term::Builtin(builtin) => Term::Builtin(builtin), + } + } + + pub fn debruijn_to_name(&mut self, _term: Term) -> anyhow::Result> { + todo!() + } + + pub fn debruijn_to_named_debruijn(&mut self, term: Term) -> Term { + match term { + Term::Var(name) => Term::Var(name.into()), + Term::Delay(term) => Term::Delay(Box::new(self.debruijn_to_named_debruijn(*term))), + Term::Lambda { + parameter_name, + body, + } => Term::Lambda { + parameter_name: parameter_name.into(), + body: Box::new(self.debruijn_to_named_debruijn(*body)), + }, + Term::Apply { function, argument } => Term::Apply { + function: Box::new(self.debruijn_to_named_debruijn(*function)), + argument: Box::new(self.debruijn_to_named_debruijn(*argument)), + }, + Term::Constant(constant) => Term::Constant(constant), + Term::Force(term) => Term::Force(Box::new(self.debruijn_to_named_debruijn(*term))), + Term::Error => Term::Error, + Term::Builtin(builtin) => Term::Builtin(builtin), + } + } + fn get_index(&mut self, unique: Unique) -> anyhow::Result { for scope in self.levels.iter().rev() { if let Some(found_level) = scope.get(&unique) { diff --git a/crates/uplc/src/flat.rs b/crates/uplc/src/flat.rs index 9d1df091..846a8b0a 100644 --- a/crates/uplc/src/flat.rs +++ b/crates/uplc/src/flat.rs @@ -7,7 +7,7 @@ use flat::{ }; use crate::{ - ast::{Constant, Name, Program, Term, Unique}, + ast::{Constant, DeBruijn, Name, NamedDeBruijn, Program, Term, Unique}, builtins::DefaultFunction, }; @@ -15,11 +15,16 @@ const BUILTIN_TAG_WIDTH: u32 = 7; const CONST_TAG_WIDTH: u32 = 4; const TERM_TAG_WIDTH: u32 = 4; -impl<'b, T> Flat<'b> for Program where T: Encode + Decode<'b> {} +pub trait Binder<'b>: Encode + Decode<'b> { + fn binder_encode(&self, e: &mut Encoder) -> Result<(), String>; + fn binder_decode(d: &mut Decoder) -> Result; +} + +impl<'b, T> Flat<'b> for Program where T: Binder<'b> {} impl<'b, T> Program where - T: Encode + Decode<'b>, + T: Binder<'b>, { // convenient so that people don't need to depend on the flat crate // directly to call programs flat function @@ -36,7 +41,10 @@ where } } -impl Encode for Program { +impl<'b, T> Encode for Program +where + T: Binder<'b>, +{ fn encode(&self, e: &mut Encoder) -> Result<(), String> { let (major, minor, patch) = self.version; @@ -52,7 +60,7 @@ impl Encode for Program { impl<'b, T> Decode<'b> for Program where - T: Decode<'b>, + T: Binder<'b>, { fn decode(d: &mut Decoder) -> Result { let version = (usize::decode(d)?, usize::decode(d)?, usize::decode(d)?); @@ -61,7 +69,10 @@ where } } -impl Encode for Term { +impl<'b, T> Encode for Term +where + T: Binder<'b>, +{ fn encode(&self, e: &mut Encoder) -> Result<(), String> { match self { Term::Var(name) => { @@ -77,7 +88,7 @@ impl Encode for Term { body, } => { encode_term_tag(2, e)?; - parameter_name.encode(e)?; + parameter_name.binder_encode(e)?; body.encode(e)?; } Term::Apply { function, argument } => { @@ -112,14 +123,14 @@ impl Encode for Term { impl<'b, T> Decode<'b> for Term where - T: Decode<'b>, + T: Binder<'b>, { fn decode(d: &mut Decoder) -> Result { match decode_term_tag(d)? { 0 => Ok(Term::Var(T::decode(d)?)), 1 => Ok(Term::Delay(Box::new(Term::decode(d)?))), 2 => Ok(Term::Lambda { - parameter_name: T::decode(d)?, + parameter_name: T::binder_decode(d)?, body: Box::new(Term::decode(d)?), }), 3 => Ok(Term::Apply { @@ -198,7 +209,7 @@ impl<'b> Decode<'b> for Unique { } impl Encode for Name { - fn encode(&self, e: &mut flat::en::Encoder) -> Result<(), String> { + fn encode(&self, e: &mut Encoder) -> Result<(), String> { self.text.encode(e)?; self.unique.encode(e)?; @@ -215,8 +226,77 @@ impl<'b> Decode<'b> for Name { } } +impl<'b> Binder<'b> for Name { + fn binder_encode(&self, e: &mut Encoder) -> Result<(), String> { + self.encode(e)?; + + Ok(()) + } + + fn binder_decode(d: &mut Decoder) -> Result { + Name::decode(d) + } +} + +impl Encode for NamedDeBruijn { + fn encode(&self, e: &mut Encoder) -> Result<(), String> { + self.text.encode(e)?; + self.index.encode(e)?; + + Ok(()) + } +} + +impl<'b> Decode<'b> for NamedDeBruijn { + fn decode(d: &mut Decoder) -> Result { + Ok(NamedDeBruijn { + text: String::decode(d)?, + index: DeBruijn::decode(d)?, + }) + } +} + +impl<'b> Binder<'b> for NamedDeBruijn { + fn binder_encode(&self, e: &mut Encoder) -> Result<(), String> { + self.text.encode(e)?; + + Ok(()) + } + + fn binder_decode(d: &mut Decoder) -> Result { + Ok(NamedDeBruijn { + text: String::decode(d)?, + index: DeBruijn::new(0), + }) + } +} + +impl Encode for DeBruijn { + fn encode(&self, e: &mut Encoder) -> Result<(), String> { + usize::from(*self).encode(e)?; + + Ok(()) + } +} + +impl<'b> Decode<'b> for DeBruijn { + fn decode(d: &mut Decoder) -> Result { + Ok(usize::decode(d)?.into()) + } +} + +impl<'b> Binder<'b> for DeBruijn { + fn binder_encode(&self, _: &mut Encoder) -> Result<(), String> { + Ok(()) + } + + fn binder_decode(_d: &mut Decoder) -> Result { + Ok(DeBruijn::new(0)) + } +} + impl Encode for DefaultFunction { - fn encode(&self, e: &mut flat::en::Encoder) -> Result<(), String> { + fn encode(&self, e: &mut Encoder) -> Result<(), String> { e.bits(BUILTIN_TAG_WIDTH as i64, self.clone() as u8); Ok(())