diff --git a/crates/uplc/src/ast.rs b/crates/uplc/src/ast.rs index db9b0c89..806b9d4f 100644 --- a/crates/uplc/src/ast.rs +++ b/crates/uplc/src/ast.rs @@ -1,4 +1,4 @@ -use crate::builtins::DefaultFunction; +use crate::{builtins::DefaultFunction, debruijn::Converter}; #[derive(Debug, Clone, PartialEq)] pub struct Program { @@ -6,6 +6,17 @@ pub struct Program { pub term: Term, } +impl TryFrom> for Program { + type Error = String; + + fn try_from(value: Program) -> Result { + Ok(Program:: { + version: value.version, + term: value.term.try_into()?, + }) + } +} + #[derive(Debug, Clone, PartialEq)] pub enum Term { // tag: 0 @@ -32,6 +43,22 @@ pub enum Term { Builtin(DefaultFunction), } +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_named_debruijn(value) + .map_err(|err| err.to_string())?; + + Ok(term) + } +} + #[derive(Debug, Clone, PartialEq)] pub enum Constant { // tag: 0 @@ -51,14 +78,66 @@ pub enum Constant { #[derive(Debug, Clone, PartialEq)] pub struct Name { pub text: String, - pub unique: isize, + pub unique: Unique, +} + +#[derive(Debug, Clone, PartialEq, Copy, Eq, Hash)] +pub struct Unique(isize); + +impl Unique { + pub fn new(unique: isize) -> Self { + Unique(unique) + } + + pub fn increment(&mut self) { + self.0 += 1; + } +} + +impl From for Unique { + fn from(i: isize) -> Self { + Unique(i) + } +} + +impl From for isize { + fn from(d: Unique) -> Self { + d.0 + } } #[derive(Debug, Clone, PartialEq)] pub struct NamedDeBruijn { pub text: String, - pub index: isize, + pub index: DeBruijn, } -#[derive(Debug, Clone, PartialEq)] -pub struct DeBruijn(isize); +#[derive(Debug, Clone, PartialEq, Copy)] +pub struct DeBruijn(u64); + +impl From for DeBruijn { + fn from(i: u64) -> Self { + DeBruijn(i) + } +} + +impl From for u64 { + fn from(d: DeBruijn) -> Self { + d.0 + } +} + +impl From for DeBruijn { + fn from(n: NamedDeBruijn) -> Self { + n.index + } +} + +impl From for NamedDeBruijn { + fn from(index: DeBruijn) -> Self { + NamedDeBruijn { + text: String::from("i"), + index, + } + } +} diff --git a/crates/uplc/src/debruijn.rs b/crates/uplc/src/debruijn.rs new file mode 100644 index 00000000..b26c3f2e --- /dev/null +++ b/crates/uplc/src/debruijn.rs @@ -0,0 +1,62 @@ +use std::collections::HashMap; + +use crate::ast::{DeBruijn, Name, NamedDeBruijn, Term, Unique}; + +struct Level(u64); + +pub(crate) struct Converter { + current_level: Level, + levels: HashMap, +} + +impl Converter { + pub(crate) fn new() -> Self { + Converter { + current_level: Level(0), + levels: HashMap::new(), + } + } + + pub(crate) fn name_to_named_debruijn( + &mut self, + term: Term, + ) -> anyhow::Result> { + let converted_term = match term { + Term::Var(Name { text, unique }) => Term::Var(NamedDeBruijn { + text, + index: self.get_index(unique)?, + }), + Term::Delay(term) => Term::Delay(Box::new(self.name_to_named_debruijn(*term)?)), + Term::Lambda { + parameter_name, + body, + } => { + todo!() + } + Term::Apply { function, argument } => Term::Apply { + function: Box::new(self.name_to_named_debruijn(*function)?), + argument: Box::new(self.name_to_named_debruijn(*argument)?), + }, + Term::Constant(constant) => Term::Constant(constant), + Term::Force(term) => Term::Force(Box::new(self.name_to_named_debruijn(*term)?)), + Term::Error => Term::Error, + Term::Builtin(builtin) => Term::Builtin(builtin), + }; + + Ok(converted_term) + } + + pub(crate) fn named_debruijn_to_name(&mut self, term: Term) -> Term { + todo!() + } + + fn get_index(&mut self, unique: Unique) -> anyhow::Result { + if let Some(found_level) = self.levels.get(&unique) { + let index = self.current_level.0 - found_level.0; + + Ok(index.into()) + } else { + anyhow::bail!("Free unique: {}", isize::from(unique)); + } + } +} diff --git a/crates/uplc/src/flat.rs b/crates/uplc/src/flat.rs index c3ce2780..9d1df091 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}, + ast::{Constant, Name, Program, Term, Unique}, builtins::DefaultFunction, }; @@ -183,6 +183,20 @@ impl<'b> Decode<'b> for Constant { } } +impl Encode for Unique { + fn encode(&self, e: &mut Encoder) -> Result<(), String> { + isize::from(*self).encode(e)?; + + Ok(()) + } +} + +impl<'b> Decode<'b> for Unique { + fn decode(d: &mut Decoder) -> Result { + Ok(isize::decode(d)?.into()) + } +} + impl Encode for Name { fn encode(&self, e: &mut flat::en::Encoder) -> Result<(), String> { self.text.encode(e)?; @@ -196,7 +210,7 @@ impl<'b> Decode<'b> for Name { fn decode(d: &mut Decoder) -> Result { Ok(Name { text: String::decode(d)?, - unique: isize::decode(d)?, + unique: Unique::decode(d)?, }) } } diff --git a/crates/uplc/src/lib.rs b/crates/uplc/src/lib.rs index e5258e37..1c0fdeb3 100644 --- a/crates/uplc/src/lib.rs +++ b/crates/uplc/src/lib.rs @@ -1,5 +1,6 @@ pub mod ast; pub mod builtins; +mod debruijn; mod flat; pub mod parser; diff --git a/crates/uplc/src/parser.rs b/crates/uplc/src/parser.rs index 28468b57..1b3d80ef 100644 --- a/crates/uplc/src/parser.rs +++ b/crates/uplc/src/parser.rs @@ -12,13 +12,13 @@ use combine::{ }; use crate::{ - ast::{Constant, Name, Program, Term}, + ast::{Constant, Name, Program, Term, Unique}, builtins::DefaultFunction, }; struct ParserState { - identifiers: HashMap, - current_unique: isize, + identifiers: HashMap, + current: Unique, } type StateStream = state::Stream; @@ -27,17 +27,20 @@ impl ParserState { fn new() -> Self { ParserState { identifiers: HashMap::new(), - current_unique: 0, + current: Unique::new(0), } } - fn intern(&mut self, text: &str) -> isize { + fn intern(&mut self, text: &str) -> Unique { if let Some(u) = self.identifiers.get(text) { *u } else { - let unique = self.current_unique; + let unique = self.current; + self.identifiers.insert(text.to_string(), unique); - self.current_unique += 1; + + self.current.increment(); + unique } }