Merge pull request #6 from txpipe/rvcas/debruijn_to_unique
convert a named debruijn to a name
This commit is contained in:
commit
b95c04a9dd
|
@ -1,7 +1,7 @@
|
|||
use std::fs;
|
||||
|
||||
use uplc::{
|
||||
ast::{DeBruijn, FakeNamedDeBruijn, Program},
|
||||
ast::{DeBruijn, Name, Program},
|
||||
parser,
|
||||
};
|
||||
|
||||
|
@ -46,7 +46,9 @@ fn main() -> anyhow::Result<()> {
|
|||
UplcCommand::Unflat { input, print } => {
|
||||
let bytes = std::fs::read(&input)?;
|
||||
|
||||
let program = Program::<FakeNamedDeBruijn>::from_flat(&bytes)?;
|
||||
let program = Program::<DeBruijn>::from_flat(&bytes)?;
|
||||
|
||||
let program: Program<Name> = program.try_into()?;
|
||||
|
||||
if print {
|
||||
println!("{:#?}", program);
|
||||
|
|
|
@ -66,12 +66,18 @@ pub enum Constant {
|
|||
/// A Name containing it's parsed textual representation
|
||||
/// and a unique id from string interning. The Name's text is
|
||||
/// interned during parsing.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Name {
|
||||
pub text: String,
|
||||
pub unique: Unique,
|
||||
}
|
||||
|
||||
impl PartialEq for Name {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.unique == other.unique
|
||||
}
|
||||
}
|
||||
|
||||
/// A unique id used for string interning.
|
||||
#[derive(Debug, Clone, PartialEq, Copy, Eq, Hash)]
|
||||
pub struct Unique(isize);
|
||||
|
@ -110,12 +116,18 @@ impl Display for Unique {
|
|||
/// Similar to `Name` but for Debruijn indices.
|
||||
/// `Name` is replaced by `NamedDebruijn` when converting
|
||||
/// program to it's debruijn form.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct NamedDeBruijn {
|
||||
pub text: String,
|
||||
pub index: DeBruijn,
|
||||
}
|
||||
|
||||
impl PartialEq for NamedDeBruijn {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.index == other.index
|
||||
}
|
||||
}
|
||||
|
||||
/// This is useful for decoding a on chain program into debruijn form.
|
||||
/// It allows for injecting fake textual names while also using Debruijn for decoding
|
||||
/// without having to loop through twice.
|
||||
|
@ -155,6 +167,10 @@ impl DeBruijn {
|
|||
pub fn new(index: usize) -> Self {
|
||||
DeBruijn(index)
|
||||
}
|
||||
|
||||
pub fn inner(&self) -> usize {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for DeBruijn {
|
||||
|
@ -169,6 +185,12 @@ impl From<DeBruijn> for usize {
|
|||
}
|
||||
}
|
||||
|
||||
impl Display for DeBruijn {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<NamedDeBruijn> for DeBruijn {
|
||||
fn from(n: NamedDeBruijn) -> Self {
|
||||
n.index
|
||||
|
|
|
@ -1,28 +1,32 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::ast::{DeBruijn, FakeNamedDeBruijn, Name, NamedDeBruijn, Term, Unique};
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
mod bimap;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Copy, Eq, Hash)]
|
||||
struct Level(usize);
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("Free Unique `{0}`")]
|
||||
FreeUnique(Unique),
|
||||
#[error("Free Index `{0}`")]
|
||||
FreeIndex(DeBruijn),
|
||||
}
|
||||
|
||||
pub struct Converter {
|
||||
current_level: Level,
|
||||
levels: Vec<HashMap<Unique, Level>>,
|
||||
levels: Vec<bimap::BiMap>,
|
||||
current_unique: Unique,
|
||||
}
|
||||
|
||||
impl Converter {
|
||||
pub fn new() -> Self {
|
||||
Converter {
|
||||
current_level: Level(0),
|
||||
levels: vec![HashMap::new()],
|
||||
levels: vec![bimap::BiMap::new()],
|
||||
current_unique: Unique::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,9 +115,93 @@ impl Converter {
|
|||
|
||||
pub fn named_debruijn_to_name(
|
||||
&mut self,
|
||||
_term: Term<NamedDeBruijn>,
|
||||
term: Term<NamedDeBruijn>,
|
||||
) -> Result<Term<Name>, Error> {
|
||||
todo!()
|
||||
let converted_term = match term {
|
||||
Term::Var(NamedDeBruijn { text, index }) => Term::Var(Name {
|
||||
text,
|
||||
unique: self.get_unique(index)?,
|
||||
}),
|
||||
Term::Delay(term) => Term::Delay(Box::new(self.named_debruijn_to_name(*term)?)),
|
||||
Term::Lambda {
|
||||
parameter_name,
|
||||
body,
|
||||
} => {
|
||||
self.declare_binder();
|
||||
|
||||
let unique = self.get_unique(parameter_name.index)?;
|
||||
|
||||
let name = Name {
|
||||
text: parameter_name.text,
|
||||
unique,
|
||||
};
|
||||
|
||||
self.start_scope();
|
||||
|
||||
let body = self.named_debruijn_to_name(*body)?;
|
||||
|
||||
self.end_scope();
|
||||
|
||||
Term::Lambda {
|
||||
parameter_name: name,
|
||||
body: Box::new(body),
|
||||
}
|
||||
}
|
||||
Term::Apply { function, argument } => Term::Apply {
|
||||
function: Box::new(self.named_debruijn_to_name(*function)?),
|
||||
argument: Box::new(self.named_debruijn_to_name(*argument)?),
|
||||
},
|
||||
Term::Constant(constant) => Term::Constant(constant),
|
||||
Term::Force(term) => Term::Force(Box::new(self.named_debruijn_to_name(*term)?)),
|
||||
Term::Error => Term::Error,
|
||||
Term::Builtin(builtin) => Term::Builtin(builtin),
|
||||
};
|
||||
|
||||
Ok(converted_term)
|
||||
}
|
||||
|
||||
pub fn debruijn_to_name(&mut self, term: Term<DeBruijn>) -> Result<Term<Name>, Error> {
|
||||
let converted_term = match term {
|
||||
Term::Var(index) => Term::Var(Name {
|
||||
text: String::from("i"),
|
||||
unique: self.get_unique(index)?,
|
||||
}),
|
||||
Term::Delay(term) => Term::Delay(Box::new(self.debruijn_to_name(*term)?)),
|
||||
Term::Lambda {
|
||||
parameter_name,
|
||||
body,
|
||||
} => {
|
||||
self.declare_binder();
|
||||
|
||||
let unique = self.get_unique(parameter_name)?;
|
||||
|
||||
let name = Name {
|
||||
text: String::from("i"),
|
||||
unique,
|
||||
};
|
||||
|
||||
self.start_scope();
|
||||
|
||||
let body = self.debruijn_to_name(*body)?;
|
||||
|
||||
self.end_scope();
|
||||
|
||||
Term::Lambda {
|
||||
parameter_name: name,
|
||||
body: Box::new(body),
|
||||
}
|
||||
}
|
||||
Term::Apply { function, argument } => Term::Apply {
|
||||
function: Box::new(self.debruijn_to_name(*function)?),
|
||||
argument: Box::new(self.debruijn_to_name(*argument)?),
|
||||
},
|
||||
Term::Constant(constant) => Term::Constant(constant),
|
||||
Term::Force(term) => Term::Force(Box::new(self.debruijn_to_name(*term)?)),
|
||||
Term::Error => Term::Error,
|
||||
Term::Builtin(builtin) => Term::Builtin(builtin),
|
||||
};
|
||||
|
||||
Ok(converted_term)
|
||||
}
|
||||
|
||||
pub fn named_debruijn_to_debruijn(&mut self, term: Term<NamedDeBruijn>) -> Term<DeBruijn> {
|
||||
|
@ -138,10 +226,6 @@ impl Converter {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn debruijn_to_name(&mut self, _term: Term<DeBruijn>) -> Result<Term<Name>, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn debruijn_to_named_debruijn(&mut self, term: Term<DeBruijn>) -> Term<NamedDeBruijn> {
|
||||
match term {
|
||||
Term::Var(name) => Term::Var(name.into()),
|
||||
|
@ -234,16 +318,36 @@ impl Converter {
|
|||
Err(Error::FreeUnique(unique))
|
||||
}
|
||||
|
||||
fn get_unique(&mut self, index: DeBruijn) -> Result<Unique, Error> {
|
||||
for scope in self.levels.iter().rev() {
|
||||
let index = Level(self.current_level.0 - index.inner());
|
||||
|
||||
if let Some(unique) = scope.get_right(&index) {
|
||||
return Ok(*unique);
|
||||
}
|
||||
}
|
||||
|
||||
Err(Error::FreeIndex(index))
|
||||
}
|
||||
|
||||
fn declare_unique(&mut self, unique: Unique) {
|
||||
let scope = &mut self.levels[self.current_level.0];
|
||||
|
||||
scope.insert(unique, self.current_level);
|
||||
}
|
||||
|
||||
fn declare_binder(&mut self) {
|
||||
let scope = &mut self.levels[self.current_level.0];
|
||||
|
||||
scope.insert(self.current_unique, self.current_level);
|
||||
|
||||
self.current_unique.increment();
|
||||
}
|
||||
|
||||
fn start_scope(&mut self) {
|
||||
self.current_level = Level(self.current_level.0 + 1);
|
||||
|
||||
self.levels.push(HashMap::new());
|
||||
self.levels.push(bimap::BiMap::new());
|
||||
}
|
||||
|
||||
fn end_scope(&mut self) {
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use crate::ast::Unique;
|
||||
|
||||
use super::Level;
|
||||
|
||||
pub struct BiMap {
|
||||
left: HashMap<Unique, Level>,
|
||||
right: HashMap<Level, Unique>,
|
||||
}
|
||||
|
||||
impl BiMap {
|
||||
pub(super) fn new() -> Self {
|
||||
BiMap {
|
||||
right: HashMap::new(),
|
||||
left: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn insert(&mut self, unique: Unique, level: Level) {
|
||||
self.left.insert(unique, level);
|
||||
self.right.insert(level, unique);
|
||||
}
|
||||
|
||||
pub(super) fn get(&self, unique: &Unique) -> Option<&Level> {
|
||||
self.left.get(unique)
|
||||
}
|
||||
|
||||
pub(super) fn get_right(&self, level: &Level) -> Option<&Unique> {
|
||||
self.right.get(level)
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/// e2e encoding/decoding tests
|
||||
use crate::{
|
||||
ast::{DeBruijn, Program},
|
||||
ast::{DeBruijn, Name, Program},
|
||||
parser,
|
||||
};
|
||||
|
||||
|
@ -11,7 +11,7 @@ fn integer() {
|
|||
|
||||
let parsed_program = parser::program(code).unwrap();
|
||||
|
||||
let debruijn_program: Program<DeBruijn> = parsed_program.try_into().unwrap();
|
||||
let debruijn_program: Program<DeBruijn> = parsed_program.clone().try_into().unwrap();
|
||||
|
||||
let decoded_program: Program<DeBruijn> = Program::from_flat(bytes).unwrap();
|
||||
|
||||
|
@ -20,6 +20,10 @@ fn integer() {
|
|||
let encoded_program = debruijn_program.to_flat().unwrap();
|
||||
|
||||
assert_eq!(encoded_program, bytes);
|
||||
|
||||
let name_program: Program<Name> = decoded_program.try_into().unwrap();
|
||||
|
||||
assert_eq!(parsed_program, name_program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -29,7 +33,7 @@ fn jpg() {
|
|||
|
||||
let parsed_program = parser::program(code).unwrap();
|
||||
|
||||
let debruijn_program: Program<DeBruijn> = parsed_program.try_into().unwrap();
|
||||
let debruijn_program: Program<DeBruijn> = parsed_program.clone().try_into().unwrap();
|
||||
|
||||
let decoded_program: Program<DeBruijn> = Program::from_flat(bytes).unwrap();
|
||||
|
||||
|
@ -38,4 +42,8 @@ fn jpg() {
|
|||
let encoded_program = debruijn_program.to_flat().unwrap();
|
||||
|
||||
assert_eq!(encoded_program, bytes);
|
||||
|
||||
let name_program: Program<Name> = decoded_program.try_into().unwrap();
|
||||
|
||||
assert_eq!(parsed_program, name_program);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue