feat: start pretty printing
This commit is contained in:
parent
b95c04a9dd
commit
5a6ba40557
|
@ -17,6 +17,12 @@ version = "1.0.57"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
|
@ -40,6 +46,12 @@ version = "1.3.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "3.1.18"
|
||||
|
@ -136,6 +148,15 @@ version = "0.2.126"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.0.1"
|
||||
|
@ -169,6 +190,18 @@ version = "0.8.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9b0efd3ba03c3a409d44d60425f279ec442bcf0b9e63ff4e410da31c8b0f69f"
|
||||
|
||||
[[package]]
|
||||
name = "pretty"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83f3aa1e3ca87d3b124db7461265ac176b40c277f37e503eaa29c9c75c037846"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"log",
|
||||
"typed-arena",
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
|
@ -211,37 +244,12 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e96acfc1b70604b8b2f1ffa4c57e59176c7dbb05d556c71ecd2f5498a1dee7f8"
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6878079b17446e4d3eba6192bb0a2950d5b14f0ed8424b852310e5a94345d0ef"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.95"
|
||||
|
@ -288,12 +296,24 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typed-arena"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0685c84d5d54d1c26f7d3eb96cd41550adb97baed141a761cf335d3d33bcd0ae"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
|
||||
|
||||
[[package]]
|
||||
name = "uplc"
|
||||
version = "0.0.2"
|
||||
|
@ -301,8 +321,7 @@ dependencies = [
|
|||
"flat-rs",
|
||||
"hex",
|
||||
"peg",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"pretty",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ use clap::{Parser, Subcommand};
|
|||
#[derive(Parser)]
|
||||
#[clap(author, version, about, long_about = None)]
|
||||
#[clap(propagate_version = true)]
|
||||
pub enum Cli {
|
||||
pub enum Args {
|
||||
/// A subcommand for working with Untyped Plutus Core
|
||||
#[clap(subcommand)]
|
||||
Uplc(UplcCommand),
|
||||
|
@ -28,10 +28,12 @@ pub enum UplcCommand {
|
|||
input: PathBuf,
|
||||
#[clap(short, long)]
|
||||
print: bool,
|
||||
#[clap(short, long)]
|
||||
out: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
impl Default for Cli {
|
||||
impl Default for Args {
|
||||
fn default() -> Self {
|
||||
Self::parse()
|
||||
}
|
|
@ -5,13 +5,15 @@ use uplc::{
|
|||
parser,
|
||||
};
|
||||
|
||||
use aiken::{Cli, UplcCommand};
|
||||
mod args;
|
||||
|
||||
use args::{Args, UplcCommand};
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let args = Cli::default();
|
||||
let args = Args::default();
|
||||
|
||||
match args {
|
||||
Cli::Uplc(uplc) => match uplc {
|
||||
Args::Uplc(uplc) => match uplc {
|
||||
UplcCommand::Flat { input, print, out } => {
|
||||
let code = std::fs::read_to_string(&input)?;
|
||||
|
||||
|
@ -22,17 +24,19 @@ fn main() -> anyhow::Result<()> {
|
|||
let bytes = program.to_flat()?;
|
||||
|
||||
if print {
|
||||
let mut output = String::new();
|
||||
|
||||
for (i, byte) in bytes.iter().enumerate() {
|
||||
print!("{:08b}", byte);
|
||||
output.push_str(&format!("{:08b}", byte));
|
||||
|
||||
if (i + 1) % 4 == 0 {
|
||||
println!();
|
||||
output.push('\n');
|
||||
} else {
|
||||
print!(" ");
|
||||
output.push(' ');
|
||||
}
|
||||
}
|
||||
|
||||
println!();
|
||||
println!("{}", output);
|
||||
} else {
|
||||
let out_name = if let Some(out) = out {
|
||||
out
|
||||
|
@ -43,15 +47,25 @@ fn main() -> anyhow::Result<()> {
|
|||
fs::write(&out_name, &bytes)?;
|
||||
}
|
||||
}
|
||||
UplcCommand::Unflat { input, print } => {
|
||||
UplcCommand::Unflat { input, print, out } => {
|
||||
let bytes = std::fs::read(&input)?;
|
||||
|
||||
let program = Program::<DeBruijn>::from_flat(&bytes)?;
|
||||
|
||||
let program: Program<Name> = program.try_into()?;
|
||||
|
||||
let pretty = program.to_pretty();
|
||||
|
||||
if print {
|
||||
println!("{:#?}", program);
|
||||
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)?;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -16,6 +16,5 @@ exclude = ["test_data/*"]
|
|||
flat-rs = { path = "../flat", version = "0.0.2" }
|
||||
hex = "0.4.3"
|
||||
peg = "0.8.0"
|
||||
strum = "0.24.0"
|
||||
strum_macros = "0.24.0"
|
||||
pretty = "0.11.3"
|
||||
thiserror = "1.0.31"
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use std::{fmt::Display, str::FromStr};
|
||||
|
||||
use flat_rs::de;
|
||||
use strum_macros::EnumString;
|
||||
|
||||
/// All the possible builtin functions in Untyped Plutus Core.
|
||||
#[repr(u8)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Debug, Clone, EnumString, PartialEq, Copy)]
|
||||
#[strum(serialize_all = "camelCase")]
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
pub enum DefaultFunction {
|
||||
// Integer functions
|
||||
AddInteger = 0,
|
||||
|
@ -28,7 +28,6 @@ pub enum DefaultFunction {
|
|||
LessThanByteString = 16,
|
||||
LessThanEqualsByteString = 17,
|
||||
// Cryptography and hash functions
|
||||
#[strum(serialize = "sha2_256")]
|
||||
Sha2_256 = 18,
|
||||
Sha3_256 = 19,
|
||||
Blake2b_256 = 20,
|
||||
|
@ -195,3 +194,132 @@ impl TryFrom<u8> for DefaultFunction {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for DefaultFunction {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
use DefaultFunction::*;
|
||||
|
||||
match s {
|
||||
"addInteger" => Ok(AddInteger),
|
||||
"subtractInteger" => Ok(SubtractInteger),
|
||||
"multiplyInteger" => Ok(MultiplyInteger),
|
||||
"divideInteger" => Ok(DivideInteger),
|
||||
"quotientInteger" => Ok(QuotientInteger),
|
||||
"remainderInteger" => Ok(RemainderInteger),
|
||||
"modInteger" => Ok(ModInteger),
|
||||
"equalsInteger" => Ok(EqualsInteger),
|
||||
"lessThanInteger" => Ok(LessThanInteger),
|
||||
"lessThanEqualsInteger" => Ok(LessThanEqualsInteger),
|
||||
"appendByteString" => Ok(AppendByteString),
|
||||
"consByteString" => Ok(ConsByteString),
|
||||
"sliceByteString" => Ok(SliceByteString),
|
||||
"lengthOfByteString" => Ok(LengthOfByteString),
|
||||
"indexByteString" => Ok(IndexByteString),
|
||||
"equalsByteString" => Ok(EqualsByteString),
|
||||
"lessThanByteString" => Ok(LessThanByteString),
|
||||
"lessThanEqualsByteString" => Ok(LessThanEqualsByteString),
|
||||
"sha2_256" => Ok(Sha2_256),
|
||||
"sha3_256" => Ok(Sha3_256),
|
||||
"blake2b_256" => Ok(Blake2b_256),
|
||||
"verifySignature" => Ok(VerifySignature),
|
||||
"verifyEcdsaSecp256k1Signature" => Ok(VerifyEcdsaSecp256k1Signature),
|
||||
"verifySchnorrSecp256k1Signature" => Ok(VerifySchnorrSecp256k1Signature),
|
||||
"appendString" => Ok(AppendString),
|
||||
"equalsString" => Ok(EqualsString),
|
||||
"encodeUtf8" => Ok(EncodeUtf8),
|
||||
"decodeUtf8" => Ok(DecodeUtf8),
|
||||
"ifThenElse" => Ok(IfThenElse),
|
||||
"chooseUnit" => Ok(ChooseUnit),
|
||||
"trace" => Ok(Trace),
|
||||
"fstPair" => Ok(FstPair),
|
||||
"sndPair" => Ok(SndPair),
|
||||
"chooseList" => Ok(ChooseList),
|
||||
"mkCons" => Ok(MkCons),
|
||||
"headList" => Ok(HeadList),
|
||||
"tailList" => Ok(TailList),
|
||||
"nullList" => Ok(NullList),
|
||||
"chooseData" => Ok(ChooseData),
|
||||
"constrData" => Ok(ConstrData),
|
||||
"mapData" => Ok(MapData),
|
||||
"listData" => Ok(ListData),
|
||||
"iData" => Ok(IData),
|
||||
"bData" => Ok(BData),
|
||||
"unConstrData" => Ok(UnConstrData),
|
||||
"unMapData" => Ok(UnMapData),
|
||||
"unListData" => Ok(UnListData),
|
||||
"unIData" => Ok(UnIData),
|
||||
"unBData" => Ok(UnBData),
|
||||
"equalsData" => Ok(EqualsData),
|
||||
"serialiseData" => Ok(SerialiseData),
|
||||
"mkPairData" => Ok(MkPairData),
|
||||
"mkNilData" => Ok(MkNilData),
|
||||
"mkNilPairData" => Ok(MkNilPairData),
|
||||
rest => Err(format!("Default Function not found - {}", rest)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for DefaultFunction {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
use DefaultFunction::*;
|
||||
|
||||
match self {
|
||||
AddInteger => write!(f, "addInteger"),
|
||||
SubtractInteger => write!(f, "subtractInteger"),
|
||||
MultiplyInteger => write!(f, "multiplyInteger"),
|
||||
DivideInteger => write!(f, "divideInteger"),
|
||||
QuotientInteger => write!(f, "quotientInteger"),
|
||||
RemainderInteger => write!(f, "remainderInteger"),
|
||||
ModInteger => write!(f, "modInteger"),
|
||||
EqualsInteger => write!(f, "equalsInteger"),
|
||||
LessThanInteger => write!(f, "lessThanInteger"),
|
||||
LessThanEqualsInteger => write!(f, "lessThanEqualsInteger"),
|
||||
AppendByteString => write!(f, "appendByteString"),
|
||||
ConsByteString => write!(f, "consByteString"),
|
||||
SliceByteString => write!(f, "sliceByteString"),
|
||||
LengthOfByteString => write!(f, "lengthOfByteString"),
|
||||
IndexByteString => write!(f, "indexByteString"),
|
||||
EqualsByteString => write!(f, "equalsByteString"),
|
||||
LessThanByteString => write!(f, "lessThanByteString"),
|
||||
LessThanEqualsByteString => write!(f, "lessThanEqualsByteString"),
|
||||
Sha2_256 => write!(f, "sha2_256"),
|
||||
Sha3_256 => write!(f, "sha3_256"),
|
||||
Blake2b_256 => write!(f, "blake2b_256"),
|
||||
VerifySignature => write!(f, "verifySignature"),
|
||||
VerifyEcdsaSecp256k1Signature => write!(f, "verifyEcdsaSecp256k1Signature"),
|
||||
VerifySchnorrSecp256k1Signature => write!(f, "verifySchnorrSecp256k1Signature"),
|
||||
AppendString => write!(f, "appendString"),
|
||||
EqualsString => write!(f, "equalsString"),
|
||||
EncodeUtf8 => write!(f, "encodeUtf8"),
|
||||
DecodeUtf8 => write!(f, "decodeUtf8"),
|
||||
IfThenElse => write!(f, "ifThenElse"),
|
||||
ChooseUnit => write!(f, "chooseUnit"),
|
||||
Trace => write!(f, "trace"),
|
||||
FstPair => write!(f, "fstPair"),
|
||||
SndPair => write!(f, "sndPair"),
|
||||
ChooseList => write!(f, "chooseList"),
|
||||
MkCons => write!(f, "mkCons"),
|
||||
HeadList => write!(f, "headList"),
|
||||
TailList => write!(f, "tailList"),
|
||||
NullList => write!(f, "nullList"),
|
||||
ChooseData => write!(f, "chooseData"),
|
||||
ConstrData => write!(f, "constrData"),
|
||||
MapData => write!(f, "mapData"),
|
||||
ListData => write!(f, "listData"),
|
||||
IData => write!(f, "iData"),
|
||||
BData => write!(f, "bData"),
|
||||
UnConstrData => write!(f, "unConstrData"),
|
||||
UnMapData => write!(f, "unMapData"),
|
||||
UnListData => write!(f, "unListData"),
|
||||
UnIData => write!(f, "unIData"),
|
||||
UnBData => write!(f, "unBData"),
|
||||
EqualsData => write!(f, "equalsData"),
|
||||
SerialiseData => write!(f, "serialiseData"),
|
||||
MkPairData => write!(f, "mkPairData"),
|
||||
MkNilData => write!(f, "mkNilData"),
|
||||
MkNilPairData => write!(f, "mkNilPairData"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ pub mod builtins;
|
|||
mod debruijn;
|
||||
mod flat;
|
||||
pub mod parser;
|
||||
mod pretty;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
use pretty::RcDoc;
|
||||
|
||||
use crate::ast::{Constant, Name, Program, Term};
|
||||
|
||||
impl Program<Name> {
|
||||
pub fn to_pretty(&self) -> String {
|
||||
let mut w = Vec::new();
|
||||
|
||||
self.to_doc().render(20, &mut w).unwrap();
|
||||
|
||||
String::from_utf8(w).unwrap()
|
||||
}
|
||||
|
||||
fn to_doc(&self) -> RcDoc<()> {
|
||||
let version = format!("{}.{}.{}", self.version.0, self.version.1, self.version.2);
|
||||
|
||||
RcDoc::text("(")
|
||||
.append(RcDoc::text("program"))
|
||||
.append(RcDoc::line())
|
||||
.append(RcDoc::text(version))
|
||||
.append(RcDoc::line())
|
||||
.append(self.term.to_doc())
|
||||
.append(RcDoc::line_())
|
||||
.append(RcDoc::text(")"))
|
||||
}
|
||||
}
|
||||
|
||||
impl Term<Name> {
|
||||
fn to_doc(&self) -> RcDoc<()> {
|
||||
match self {
|
||||
Term::Var(name) => RcDoc::text(format!("{}_{}", name.text, name.unique)),
|
||||
Term::Delay(term) => RcDoc::text("(")
|
||||
.append(RcDoc::line_())
|
||||
.append(RcDoc::text("delay"))
|
||||
.append(RcDoc::line())
|
||||
.append(term.to_doc())
|
||||
.append(RcDoc::line_())
|
||||
.append(RcDoc::text(")")),
|
||||
Term::Lambda {
|
||||
parameter_name,
|
||||
body,
|
||||
} => RcDoc::text("(")
|
||||
.append(RcDoc::line_())
|
||||
.append(RcDoc::text(format!(
|
||||
"{}_{}",
|
||||
parameter_name.text, parameter_name.unique
|
||||
)))
|
||||
.append(RcDoc::line())
|
||||
.append(body.to_doc())
|
||||
.append(RcDoc::line_())
|
||||
.append(RcDoc::text(")")),
|
||||
Term::Apply { function, argument } => RcDoc::text("[")
|
||||
.append(RcDoc::line_())
|
||||
.append(function.to_doc())
|
||||
.append(RcDoc::line())
|
||||
.append(argument.to_doc())
|
||||
.append(RcDoc::line_())
|
||||
.append(RcDoc::text("]")),
|
||||
Term::Constant(constant) => RcDoc::text("(")
|
||||
.append(RcDoc::text("con"))
|
||||
.append(RcDoc::text(" "))
|
||||
.append(constant.to_doc())
|
||||
.append(RcDoc::text(")")),
|
||||
Term::Force(term) => RcDoc::text("(")
|
||||
.append(RcDoc::line_())
|
||||
.append(RcDoc::text("force"))
|
||||
.append(RcDoc::line())
|
||||
.append(term.to_doc())
|
||||
.append(RcDoc::line_())
|
||||
.append(RcDoc::text(")")),
|
||||
Term::Error => RcDoc::text("(")
|
||||
.append(RcDoc::line_())
|
||||
.append(RcDoc::text("error"))
|
||||
.append(RcDoc::line_())
|
||||
.append(RcDoc::text(")")),
|
||||
Term::Builtin(builtin) => RcDoc::text("(")
|
||||
.append(RcDoc::line_())
|
||||
.append(RcDoc::text("builtin"))
|
||||
.append(RcDoc::line())
|
||||
.append(RcDoc::text(builtin.to_string()))
|
||||
.append(RcDoc::line_())
|
||||
.append(RcDoc::text(")")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Constant {
|
||||
fn to_doc(&self) -> RcDoc<()> {
|
||||
match self {
|
||||
Constant::Integer(i) => RcDoc::text("integer")
|
||||
.append(RcDoc::space())
|
||||
.append(RcDoc::as_string(i)),
|
||||
Constant::ByteString(bs) => RcDoc::text("bytestring")
|
||||
.append(RcDoc::space())
|
||||
.append(RcDoc::text(hex::encode(bs))),
|
||||
Constant::String(s) => RcDoc::text("string")
|
||||
.append(RcDoc::space())
|
||||
.append(RcDoc::text(s)),
|
||||
Constant::Char(c) => unimplemented!("char: {}", c),
|
||||
Constant::Unit => RcDoc::text("unit")
|
||||
.append(RcDoc::space())
|
||||
.append(RcDoc::text("()")),
|
||||
Constant::Bool(b) => RcDoc::text("bool")
|
||||
.append(RcDoc::space())
|
||||
.append(RcDoc::text(if *b { "true" } else { "false" })),
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue