diff --git a/crates/aiken/src/cmd/uplc/encode.rs b/crates/aiken/src/cmd/uplc/encode.rs index fb7c8a13..311bbc92 100644 --- a/crates/aiken/src/cmd/uplc/encode.rs +++ b/crates/aiken/src/cmd/uplc/encode.rs @@ -57,7 +57,7 @@ pub fn exec( } } -fn encode<'a, T>(program: Program, cbor: bool, hex: bool) -> miette::Result<()> +pub(crate) fn encode<'a, T>(program: Program, cbor: bool, hex: bool) -> miette::Result<()> where T: Binder<'a> + std::fmt::Debug, { diff --git a/crates/aiken/src/cmd/uplc/mod.rs b/crates/aiken/src/cmd/uplc/mod.rs index 7e5b9260..e8293c7f 100644 --- a/crates/aiken/src/cmd/uplc/mod.rs +++ b/crates/aiken/src/cmd/uplc/mod.rs @@ -2,6 +2,7 @@ mod decode; mod encode; mod eval; mod fmt; +mod shrink; use clap::{Subcommand, ValueEnum}; @@ -21,6 +22,8 @@ pub enum Cmd { Encode(encode::Args), #[clap(alias = "unflat")] Decode(decode::Args), + #[clap(alias = "optimize")] + Shrink(shrink::Args) } pub fn exec(cmd: Cmd) -> miette::Result<()> { @@ -29,5 +32,6 @@ pub fn exec(cmd: Cmd) -> miette::Result<()> { Cmd::Eval(args) => eval::exec(args), Cmd::Encode(args) => encode::exec(args), Cmd::Decode(args) => decode::exec(args), + Cmd::Shrink(args) => shrink::exec(args), } } diff --git a/crates/aiken/src/cmd/uplc/shrink.rs b/crates/aiken/src/cmd/uplc/shrink.rs new file mode 100644 index 00000000..9f146f37 --- /dev/null +++ b/crates/aiken/src/cmd/uplc/shrink.rs @@ -0,0 +1,96 @@ +use miette::IntoDiagnostic; +use std::{path::PathBuf}; +use uplc::ast::{DeBruijn, Name, NamedDeBruijn, Program}; +use uplc::optimize::aiken_optimize_and_intern; + +use super::{encode, Format}; + +#[derive(clap::Args)] +/// Shrink / Optimize UPLC code using a variety of optimization steps +pub struct Args { + /// Flat encoded Untyped Plutus Core file + input: PathBuf, + + // Format to convert from + #[clap(long, default_value = "debruijn")] + from: Format, + + // Format to convert into + #[clap(long, default_value = "debruijn")] + to: Format, + + /// Input file contains cbor encoded flat bytes + #[clap(short, long)] + cbor: bool, + + /// Input file contents will be hex decoded + #[clap(long)] + hex: bool, +} + +pub fn exec( + Args { + input, + from, + to, + cbor, + hex, + }: Args, +) -> miette::Result<()> { + let bytes = if hex { + let hex_bytes = std::fs::read_to_string(&input).into_diagnostic()?; + + hex::decode(hex_bytes.trim()).into_diagnostic()? + } else { + std::fs::read(&input).into_diagnostic()? + }; + + let program: Program = match from { + Format::Name => { + if cbor { + let mut flat_buffer = Vec::new(); + Program::from_cbor(&bytes, &mut flat_buffer).into_diagnostic()? + } else { + Program::from_flat(&bytes).into_diagnostic()? + } + } + Format::NamedDebruijn => { + let program: Program = if cbor { + let mut flat_buffer = Vec::new(); + Program::from_cbor(&bytes, &mut flat_buffer).into_diagnostic()? + } else { + Program::from_flat(&bytes).into_diagnostic()? + }; + + program.try_into().unwrap() + + } + Format::Debruijn => { + let program: Program = if cbor { + let mut flat_buffer = Vec::new(); + Program::from_cbor(&bytes, &mut flat_buffer).into_diagnostic()? + } else { + Program::from_flat(&bytes).into_diagnostic()? + }; + + program.try_into().unwrap() + + } + }; + + let optimized_program = aiken_optimize_and_intern(program); + + match to { + Format::Name => encode::encode(optimized_program, cbor, hex), + Format::NamedDebruijn => { + let program: Program = optimized_program.try_into().into_diagnostic()?; + + encode::encode(program, cbor, hex) + } + Format::Debruijn => { + let program: Program = optimized_program.try_into().into_diagnostic()?; + + encode::encode(program, cbor, hex) + } + } +}