diff --git a/crates/aiken/src/cmd/uplc/decode.rs b/crates/aiken/src/cmd/uplc/decode.rs new file mode 100644 index 00000000..226f56f3 --- /dev/null +++ b/crates/aiken/src/cmd/uplc/decode.rs @@ -0,0 +1,78 @@ +use miette::IntoDiagnostic; +use std::{path::PathBuf, println}; +use uplc::ast::{DeBruijn, Name, NamedDeBruijn, Program}; + +use super::Format; + +#[derive(clap::Args)] +/// Decode flat bytes to textual Untyped Plutus Core +pub struct Args { + /// Flat encoded Untyped Plutus Core file + input: PathBuf, + + // Format to convert from + #[clap(long, default_value = "debruijn")] + from: 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, + cbor, + hex, + }: Args, +) -> miette::Result<()> { + let bytes = if hex { + let hex_bytes = std::fs::read_to_string(&input).into_diagnostic()?; + + hex::decode(hex_bytes).into_diagnostic()? + } else { + std::fs::read(&input).into_diagnostic()? + }; + + let pretty_uplc = match from { + Format::Name => { + 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.to_pretty() + } + 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.to_pretty() + } + 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.to_pretty() + } + }; + + println!("{pretty_uplc}"); + + Ok(()) +} diff --git a/crates/aiken/src/cmd/uplc/encode.rs b/crates/aiken/src/cmd/uplc/encode.rs new file mode 100644 index 00000000..fb7c8a13 --- /dev/null +++ b/crates/aiken/src/cmd/uplc/encode.rs @@ -0,0 +1,83 @@ +use miette::IntoDiagnostic; +use std::{ + io::{self, Write}, + path::PathBuf, +}; +use uplc::{ + ast::{DeBruijn, NamedDeBruijn, Program}, + flat::Binder, + parser, +}; + +use super::Format; + +/// Encode textual Untyped Plutus Core to flat bytes +#[derive(clap::Args)] +pub struct Args { + /// Textual Untyped Plutus Core file + input: PathBuf, + + // Format to convert to + #[clap(long, default_value = "debruijn")] + to: Format, + + /// Further encode the flat bytes as cbor bytes + #[clap(short, long)] + cbor: bool, + + /// Hex encode the bytes + #[clap(long)] + hex: bool, +} + +pub fn exec( + Args { + input, + to, + cbor, + hex, + }: Args, +) -> miette::Result<()> { + let code = std::fs::read_to_string(input).into_diagnostic()?; + + let program = parser::program(&code).into_diagnostic()?; + + match to { + Format::Name => encode(program, cbor, hex), + Format::NamedDebruijn => { + let program: Program = program.try_into().into_diagnostic()?; + + encode(program, cbor, hex) + } + Format::Debruijn => { + let program: Program = program.try_into().into_diagnostic()?; + + encode(program, cbor, hex) + } + } +} + +fn encode<'a, T>(program: Program, cbor: bool, hex: bool) -> miette::Result<()> +where + T: Binder<'a> + std::fmt::Debug, +{ + let mut stdout = io::stdout(); + + let bytes = if cbor { + program.to_cbor().into_diagnostic()? + } else { + program.to_flat().into_diagnostic()? + }; + + if hex { + let bytes_hex = hex::encode(bytes); + + print!("{bytes_hex}"); + } else { + stdout.write_all(&bytes).into_diagnostic()?; + } + + stdout.flush().into_diagnostic()?; + + Ok(()) +} diff --git a/crates/aiken/src/cmd/uplc/flat.rs b/crates/aiken/src/cmd/uplc/flat.rs deleted file mode 100644 index ced99d4c..00000000 --- a/crates/aiken/src/cmd/uplc/flat.rs +++ /dev/null @@ -1,83 +0,0 @@ -use miette::IntoDiagnostic; -use std::{fmt::Write, fs, path::PathBuf}; -use uplc::{ - ast::{DeBruijn, Program}, - parser, -}; - -#[derive(clap::Args)] -/// Encode textual Untyped Plutus Core to flat bytes -pub struct Args { - /// Textual Untyped Plutus Core file - input: PathBuf, - - /// Output file name - #[clap(short, long)] - out: Option, - - /// Print output instead of saving to file - #[clap(short, long)] - print: bool, - - #[clap(short, long)] - cbor_hex: bool, -} - -pub fn exec( - Args { - input, - out, - print, - cbor_hex, - }: Args, -) -> miette::Result<()> { - let code = std::fs::read_to_string(&input).into_diagnostic()?; - - let program = parser::program(&code).into_diagnostic()?; - - let program = Program::::try_from(program).into_diagnostic()?; - - if !cbor_hex { - let bytes = program.to_flat().into_diagnostic()?; - - if print { - let mut output = String::new(); - - for (i, byte) in bytes.iter().enumerate() { - let _ = write!(output, "{byte:08b}"); - - if (i + 1) % 4 == 0 { - output.push('\n'); - } else { - output.push(' '); - } - } - - println!("{output}"); - } else { - let out_name = if let Some(out) = out { - out - } else { - format!("{}.flat", input.file_stem().unwrap().to_str().unwrap()) - }; - - fs::write(out_name, &bytes).into_diagnostic()?; - } - } else { - let cbor = program.to_hex().into_diagnostic()?; - - if print { - println!("{}", &cbor); - } else { - let out_name = if let Some(out) = out { - out - } else { - format!("{}.cbor", input.file_stem().unwrap().to_str().unwrap()) - }; - - fs::write(out_name, &cbor).into_diagnostic()?; - } - } - - Ok(()) -} diff --git a/crates/aiken/src/cmd/uplc/mod.rs b/crates/aiken/src/cmd/uplc/mod.rs index edb1c56b..7e5b9260 100644 --- a/crates/aiken/src/cmd/uplc/mod.rs +++ b/crates/aiken/src/cmd/uplc/mod.rs @@ -1,24 +1,33 @@ +mod decode; +mod encode; mod eval; -mod flat; mod fmt; -mod unflat; -use clap::Subcommand; +use clap::{Subcommand, ValueEnum}; + +#[derive(Copy, Clone, ValueEnum)] +pub(super) enum Format { + Name, + NamedDebruijn, + Debruijn, +} /// Commands for working with untyped Plutus-core #[derive(Subcommand)] pub enum Cmd { Fmt(fmt::Args), Eval(eval::Args), - Flat(flat::Args), - Unflat(unflat::Args), + #[clap(alias = "flat")] + Encode(encode::Args), + #[clap(alias = "unflat")] + Decode(decode::Args), } pub fn exec(cmd: Cmd) -> miette::Result<()> { match cmd { Cmd::Fmt(args) => fmt::exec(args), Cmd::Eval(args) => eval::exec(args), - Cmd::Flat(args) => flat::exec(args), - Cmd::Unflat(args) => unflat::exec(args), + Cmd::Encode(args) => encode::exec(args), + Cmd::Decode(args) => decode::exec(args), } } diff --git a/crates/aiken/src/cmd/uplc/unflat.rs b/crates/aiken/src/cmd/uplc/unflat.rs deleted file mode 100644 index d2020385..00000000 --- a/crates/aiken/src/cmd/uplc/unflat.rs +++ /dev/null @@ -1,61 +0,0 @@ -use miette::IntoDiagnostic; -use std::{fs, path::PathBuf}; -use uplc::ast::{DeBruijn, Name, Program}; - -#[derive(clap::Args)] -/// Decode flat bytes to textual Untyped Plutus Core -pub struct Args { - /// Flat encoded Untyped Plutus Core file - input: PathBuf, - - /// Output file name - #[clap(short, long)] - out: Option, - - /// Print output instead of saving to file - #[clap(short, long)] - print: bool, - - #[clap(short, long)] - cbor_hex: bool, -} - -pub fn exec( - Args { - input, - out, - print, - cbor_hex, - }: Args, -) -> miette::Result<()> { - let program = if cbor_hex { - let cbor = std::fs::read_to_string(&input).into_diagnostic()?; - - let mut cbor_buffer = Vec::new(); - let mut flat_buffer = Vec::new(); - - Program::::from_hex(cbor.trim(), &mut cbor_buffer, &mut flat_buffer) - .into_diagnostic()? - } else { - let bytes = std::fs::read(&input).into_diagnostic()?; - - Program::::from_flat(&bytes).into_diagnostic()? - }; - - let program: Program = program.try_into().into_diagnostic()?; - - let pretty = program.to_pretty(); - - if print { - println!("{pretty}"); - } else { - let out_name = if let Some(out) = out { - out - } else { - format!("{}.uplc", input.file_stem().unwrap().to_str().unwrap()) - }; - - fs::write(out_name, pretty).into_diagnostic()?; - } - Ok(()) -} diff --git a/crates/uplc/src/lib.rs b/crates/uplc/src/lib.rs index 8f3d7800..e7a0dac3 100644 --- a/crates/uplc/src/lib.rs +++ b/crates/uplc/src/lib.rs @@ -2,7 +2,7 @@ pub mod ast; pub mod builder; pub mod builtins; mod debruijn; -mod flat; +pub mod flat; pub mod machine; pub mod optimize; pub mod parser; diff --git a/examples/hello_world/.gitignore b/examples/hello_world/.gitignore index f68e5eab..a0f888da 100644 --- a/examples/hello_world/.gitignore +++ b/examples/hello_world/.gitignore @@ -1,3 +1,4 @@ +artifacts/ build/ *.sk *.addr diff --git a/examples/hello_world/plutus.json b/examples/hello_world/plutus.json index 9260b7cb..31683275 100644 --- a/examples/hello_world/plutus.json +++ b/examples/hello_world/plutus.json @@ -20,8 +20,8 @@ "$ref": "#/definitions/hello_world~1Redeemer" } }, - "compiledCode": "58dd0100003232323232323232222533300632323232533300a002100114a06464660026eb0cc010c014cc010c014019200048040dd7198021802804240006002002444a66601e00429404c8c94ccc038cdc78010018a5113330050050010033012003375c602000466e3cdd71980098010022400091010d48656c6c6f2c20576f726c64210022323330010014800000c888cccc030cdc3802001008119980200219b8000348008c0480040048c024dd50008a4c2c6002002444a66600e004293099802980098040011998018019804801000ab9a5736aae7955cfaba15745", - "hash": "46872294cadbacb2c3214086c0129ede75cf9f767e95a449f996685f" + "compiledCode": "5901ec01000032323232323232323232322223232533300a3232533300c002100114a066646002002444a66602400429404c8c94ccc040cdc78010018a5113330050050010033015003375c60260046eb0cc01cc024cc01cc024011200048040dd71980398048012400066e3cdd7198031804001240009110d48656c6c6f2c20576f726c642100149858c8014c94ccc028cdc3a400000226464a66602060240042930a99806a49334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016375c6020002601000a2a660169212b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e7400163008004320033253330093370e900000089919299980798088010a4c2a66018921334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016375c601e002600e0062a660149212b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300700233001001480008888cccc01ccdc38008018061199980280299b8000448008c0380040080088c018dd5000918021baa0015734ae7155ceaab9e5573eae855d11", + "hash": "f3f821d122b041244de074b9554c7dbcc62f34f62426344c0d0b4c86" } ], "definitions": {