feat: debruijn conversions and binder

Co-authored-by: Kasey White <kwhitemsg@gmail.com>
This commit is contained in:
rvcas 2022-06-04 11:15:34 -04:00
parent 2ad630de90
commit 2f51b23e7e
No known key found for this signature in database
GPG Key ID: C09B64E263F7D68C
5 changed files with 314 additions and 31 deletions

View File

@ -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<NamedDeBruijn> = program.try_into().unwrap();
let program_nd: Program<NamedDeBruijn> = 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<DeBruijn> = 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(())
}

View File

@ -1,3 +1,3 @@
(program 11.22.33
(lam x (lam x y))
(lam x (lam x x))
)

View File

@ -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<usize> for DeBruijn {
fn from(i: usize) -> Self {
DeBruijn(i)
@ -126,17 +132,6 @@ impl TryFrom<Program<Name>> for Program<NamedDeBruijn> {
}
}
impl TryFrom<Program<NamedDeBruijn>> for Program<Name> {
type Error = String;
fn try_from(value: Program<NamedDeBruijn>) -> Result<Self, Self::Error> {
Ok(Program::<Name> {
version: value.version,
term: value.term.try_into()?,
})
}
}
impl TryFrom<Term<Name>> for Term<NamedDeBruijn> {
type Error = String;
@ -153,6 +148,42 @@ impl TryFrom<Term<Name>> for Term<NamedDeBruijn> {
}
}
impl TryFrom<Program<Name>> for Program<DeBruijn> {
type Error = String;
fn try_from(value: Program<Name>) -> Result<Self, Self::Error> {
Ok(Program::<DeBruijn> {
version: value.version,
term: value.term.try_into()?,
})
}
}
impl TryFrom<Term<Name>> for Term<DeBruijn> {
type Error = String;
fn try_from(value: Term<Name>) -> Result<Self, <Term<DeBruijn> as TryFrom<Term<Name>>>::Error> {
let mut converter = Converter::new();
let term = converter
.name_to_debruijn(value)
.map_err(|err| err.to_string())?;
Ok(term)
}
}
impl TryFrom<Program<NamedDeBruijn>> for Program<Name> {
type Error = String;
fn try_from(value: Program<NamedDeBruijn>) -> Result<Self, Self::Error> {
Ok(Program::<Name> {
version: value.version,
term: value.term.try_into()?,
})
}
}
impl TryFrom<Term<NamedDeBruijn>> for Term<Name> {
type Error = String;
@ -168,3 +199,64 @@ impl TryFrom<Term<NamedDeBruijn>> for Term<Name> {
Ok(term)
}
}
impl From<Program<NamedDeBruijn>> for Program<DeBruijn> {
fn from(value: Program<NamedDeBruijn>) -> Self {
Program::<DeBruijn> {
version: value.version,
term: value.term.into(),
}
}
}
impl From<Term<NamedDeBruijn>> for Term<DeBruijn> {
fn from(value: Term<NamedDeBruijn>) -> Self {
let mut converter = Converter::new();
converter.named_debruijn_to_debruijn(value)
}
}
impl TryFrom<Program<DeBruijn>> for Program<Name> {
type Error = String;
fn try_from(value: Program<DeBruijn>) -> Result<Self, Self::Error> {
Ok(Program::<Name> {
version: value.version,
term: value.term.try_into()?,
})
}
}
impl TryFrom<Term<DeBruijn>> for Term<Name> {
type Error = String;
fn try_from(
value: Term<DeBruijn>,
) -> Result<Self, <Term<Name> as TryFrom<Term<DeBruijn>>>::Error> {
let mut converter = Converter::new();
let term = converter
.debruijn_to_name(value)
.map_err(|err| err.to_string())?;
Ok(term)
}
}
impl From<Program<DeBruijn>> for Program<NamedDeBruijn> {
fn from(value: Program<DeBruijn>) -> Self {
Program::<NamedDeBruijn> {
version: value.version,
term: value.term.into(),
}
}
}
impl From<Term<DeBruijn>> for Term<NamedDeBruijn> {
fn from(value: Term<DeBruijn>) -> Self {
let mut converter = Converter::new();
converter.debruijn_to_named_debruijn(value)
}
}

View File

@ -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<HashMap<Unique, Level>>,
}
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<Name>,
) -> anyhow::Result<Term<NamedDeBruijn>> {
@ -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<Name>) -> anyhow::Result<Term<DeBruijn>> {
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<NamedDeBruijn>,
) -> anyhow::Result<Term<Name>> {
todo!()
}
pub fn named_debruijn_to_debruijn(&mut self, term: Term<NamedDeBruijn>) -> Term<DeBruijn> {
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<DeBruijn>) -> anyhow::Result<Term<Name>> {
todo!()
}
pub fn debruijn_to_named_debruijn(&mut self, term: Term<DeBruijn>) -> Term<NamedDeBruijn> {
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<DeBruijn> {
for scope in self.levels.iter().rev() {
if let Some(found_level) = scope.get(&unique) {

View File

@ -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<T> 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<Self, String>;
}
impl<'b, T> Flat<'b> for Program<T> where T: Binder<'b> {}
impl<'b, T> Program<T>
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<T: Encode> Encode for Program<T> {
impl<'b, T> Encode for Program<T>
where
T: Binder<'b>,
{
fn encode(&self, e: &mut Encoder) -> Result<(), String> {
let (major, minor, patch) = self.version;
@ -52,7 +60,7 @@ impl<T: Encode> Encode for Program<T> {
impl<'b, T> Decode<'b> for Program<T>
where
T: Decode<'b>,
T: Binder<'b>,
{
fn decode(d: &mut Decoder) -> Result<Self, String> {
let version = (usize::decode(d)?, usize::decode(d)?, usize::decode(d)?);
@ -61,7 +69,10 @@ where
}
}
impl<T: Encode> Encode for Term<T> {
impl<'b, T> Encode for Term<T>
where
T: Binder<'b>,
{
fn encode(&self, e: &mut Encoder) -> Result<(), String> {
match self {
Term::Var(name) => {
@ -77,7 +88,7 @@ impl<T: Encode> Encode for Term<T> {
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<T: Encode> Encode for Term<T> {
impl<'b, T> Decode<'b> for Term<T>
where
T: Decode<'b>,
T: Binder<'b>,
{
fn decode(d: &mut Decoder) -> Result<Self, String> {
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<Self, String> {
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<Self, String> {
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<Self, String> {
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<Self, String> {
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<Self, String> {
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(())