diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 16b14106..8b36f337 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -1,4 +1,7 @@ -use uplc::parser; +use uplc::{ + ast::{NamedDeBruijn, Program}, + parser, +}; use neptune::Cli; @@ -13,13 +16,17 @@ fn main() -> anyhow::Result<()> { let flat_bytes = program.to_flat()?; + print!("flat bits: "); + for byte in flat_bytes { print!("{:08b} ", byte); } println!(); - println!("{}", program.flat_hex()?); + let program: Program = program.try_into().unwrap(); + + println!("{:#?}", program); Ok(()) } diff --git a/crates/uplc/example/integer.uplc b/crates/uplc/example/integer.uplc index 7e4c5e38..b00bace0 100644 --- a/crates/uplc/example/integer.uplc +++ b/crates/uplc/example/integer.uplc @@ -1,3 +1,3 @@ (program 11.22.33 - (con integer 11) + (lam x x) ) \ No newline at end of file diff --git a/crates/uplc/src/ast.rs b/crates/uplc/src/ast.rs index 806b9d4f..a5cfefc2 100644 --- a/crates/uplc/src/ast.rs +++ b/crates/uplc/src/ast.rs @@ -6,17 +6,6 @@ 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 @@ -43,22 +32,6 @@ 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 @@ -141,3 +114,57 @@ impl From for NamedDeBruijn { } } } + +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 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_named_debruijn(value) + .map_err(|err| err.to_string())?; + + Ok(term) + } +} + +impl TryFrom> for Term { + type Error = String; + + fn try_from( + value: Term, + ) -> Result as TryFrom>>::Error> { + let mut converter = Converter::new(); + + let term = converter + .named_debruijn_to_name(value) + .map_err(|err| err.to_string())?; + + Ok(term) + } +} diff --git a/crates/uplc/src/debruijn.rs b/crates/uplc/src/debruijn.rs index b26c3f2e..16455e9f 100644 --- a/crates/uplc/src/debruijn.rs +++ b/crates/uplc/src/debruijn.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use crate::ast::{DeBruijn, Name, NamedDeBruijn, Term, Unique}; +#[derive(Debug, Copy, Clone)] struct Level(u64); pub(crate) struct Converter { @@ -31,7 +32,21 @@ impl Converter { parameter_name, body, } => { - todo!() + self.declare_unique(parameter_name.unique); + + let index = self.get_index(parameter_name.unique)?; + + let name = NamedDeBruijn { + text: parameter_name.text, + index, + }; + + self.with_scope(); + + Term::Lambda { + parameter_name: name, + body: Box::new(self.name_to_named_debruijn(*body)?), + } } Term::Apply { function, argument } => Term::Apply { function: Box::new(self.name_to_named_debruijn(*function)?), @@ -46,7 +61,10 @@ impl Converter { Ok(converted_term) } - pub(crate) fn named_debruijn_to_name(&mut self, term: Term) -> Term { + pub(crate) fn named_debruijn_to_name( + &mut self, + _term: Term, + ) -> anyhow::Result> { todo!() } @@ -59,4 +77,12 @@ impl Converter { anyhow::bail!("Free unique: {}", isize::from(unique)); } } + + fn declare_unique(&mut self, unique: Unique) { + self.levels.insert(unique, self.current_level); + } + + fn with_scope(&mut self) { + self.current_level = Level(self.current_level.0 + 1); + } } diff --git a/crates/uplc/src/parser.rs b/crates/uplc/src/parser.rs index 1b3d80ef..5e58f90b 100644 --- a/crates/uplc/src/parser.rs +++ b/crates/uplc/src/parser.rs @@ -102,6 +102,7 @@ where Input::Error: ParseError, { opaque!(no_partial(choice(( + attempt(var()), attempt(delay()), attempt(lambda()), attempt(apply()), @@ -112,6 +113,21 @@ where )))) } +fn var() -> impl Parser, Output = Term> +where + Input: Stream, + Input::Error: ParseError, +{ + (many1(alpha_num()), spaces()).map_input( + |(text, _): (String, _), input: &mut StateStream| { + Term::Var(Name { + unique: input.state.intern(&text), + text, + }) + }, + ) +} + fn delay() -> impl Parser, Output = Term> where Input: Stream, @@ -147,21 +163,21 @@ where Input: Stream, Input::Error: ParseError, { + let name = many1(alpha_num()).map_input(|text: String, input: &mut StateStream| Name { + unique: input.state.intern(&text), + text, + }); + between( token('('), token(')'), string("lam") .with(skip_many1(space())) - .with((many1(alpha_num()), skip_many1(space()), term())) - .map_input( - |(parameter_name, _, term): (String, _, Term), input| Term::Lambda { - parameter_name: Name { - unique: input.state.intern(¶meter_name), - text: parameter_name, - }, - body: Box::new(term), - }, - ), + .with((name, skip_many1(space()), term())) + .map(|(parameter_name, _, term)| Term::Lambda { + parameter_name, + body: Box::new(term), + }), ) }