chore: document somethings

This commit is contained in:
rvcas 2022-06-14 17:27:27 -04:00
parent 984c253f31
commit dc4246244d
No known key found for this signature in database
GPG Key ID: C09B64E263F7D68C
7 changed files with 78 additions and 2 deletions

View File

@ -2,8 +2,28 @@
A cardano smart contract language and toolchain A cardano smart contract language and toolchain
## Install
For now you'll need rust installed, see [rustup](https://rustup.rs).
`cargo install aiken`
## Usage
For now the command line application can only encode/decode Untyped Plutus Core
to/from it's on chain format. See the roadmap below for a list of planned features and goals.
```sh
# compile an untyped plutus core program
aiken uplc flat program.uplc
```
## Roadmap ## Roadmap
In general, the goal is to port everything we need for plutus to
Rust. This will be needed if we ever want to build a full node in
Rust. Since we will have these tools natively in Rust, we plan on
building a new high level language for writing smart contracts on Cardano.
These are generic milestones and the listed ordering These are generic milestones and the listed ordering
is not necessariy the implementation order or full scope. is not necessariy the implementation order or full scope.

View File

@ -2,21 +2,28 @@ use std::path::PathBuf;
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
/// Cardano smart contract toolchain
#[derive(Parser)] #[derive(Parser)]
#[clap(author, version, about, long_about = None)] #[clap(author, version, about, long_about = None)]
#[clap(propagate_version = true)] #[clap(propagate_version = true)]
pub enum Cli { pub enum Cli {
/// A subcommand for working with Untyped Plutus Core
#[clap(subcommand)] #[clap(subcommand)]
Uplc(UplcCommand), Uplc(UplcCommand),
} }
/// Commands for working with Untyped Plutus Core
#[derive(Subcommand)] #[derive(Subcommand)]
pub enum UplcCommand { pub enum UplcCommand {
/// Encode textual Untyped Plutus Core to flat bytes
Flat { Flat {
input: PathBuf, input: PathBuf,
#[clap(short, long)] #[clap(short, long)]
print: bool, print: bool,
#[clap(short, long)]
out: Option<String>,
}, },
/// Decode flat bytes to textual Untyped Plutus Core
Unflat { Unflat {
input: PathBuf, input: PathBuf,
#[clap(short, long)] #[clap(short, long)]

View File

@ -1,3 +1,5 @@
use std::fs;
use uplc::{ use uplc::{
ast::{DeBruijn, FakeNamedDeBruijn, Program}, ast::{DeBruijn, FakeNamedDeBruijn, Program},
parser, parser,
@ -10,7 +12,7 @@ fn main() -> anyhow::Result<()> {
match args { match args {
Cli::Uplc(uplc) => match uplc { Cli::Uplc(uplc) => match uplc {
UplcCommand::Flat { input, print } => { UplcCommand::Flat { input, print, out } => {
let code = std::fs::read_to_string(&input)?; let code = std::fs::read_to_string(&input)?;
let program = parser::program(&code)?; let program = parser::program(&code)?;
@ -31,6 +33,14 @@ fn main() -> anyhow::Result<()> {
} }
println!(); println!();
} 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)?;
} }
} }
UplcCommand::Unflat { input, print } => { UplcCommand::Unflat { input, print } => {

View File

@ -5,12 +5,20 @@ use crate::{
debruijn::{self, Converter}, debruijn::{self, Converter},
}; };
/// This represents a program in Untyped Plutus Core.
/// A program contains a version tuple and a term.
/// It is generic because Term requires a generic type.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Program<T> { pub struct Program<T> {
pub version: (usize, usize, usize), pub version: (usize, usize, usize),
pub term: Term<T>, pub term: Term<T>,
} }
/// This represents a term in Untyped Plutus Core.
/// We need a generic type for the different forms that a program may be in.
/// Specifically, `Var` and `parameter_name` in `Lambda` can be a `Name`,
/// `NamedDebruijn`, or `DeBruijn`. When encoded to flat for on chain usage
/// we must encode using the `DeBruijn` form.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum Term<T> { pub enum Term<T> {
// tag: 0 // tag: 0
@ -37,6 +45,8 @@ pub enum Term<T> {
Builtin(DefaultFunction), Builtin(DefaultFunction),
} }
/// A container for the various constants that are available
/// in Untyped Plutus Core. Used in the `Constant` variant of `Term`.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum Constant { pub enum Constant {
// tag: 0 // tag: 0
@ -53,20 +63,27 @@ pub enum Constant {
Bool(bool), Bool(bool),
} }
/// A Name containing it's parsed textual representation
/// and a unique id from string interning. The Name's text is
/// interned during parsing.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Name { pub struct Name {
pub text: String, pub text: String,
pub unique: Unique, pub unique: Unique,
} }
/// A unique id used for string interning.
#[derive(Debug, Clone, PartialEq, Copy, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Copy, Eq, Hash)]
pub struct Unique(isize); pub struct Unique(isize);
impl Unique { impl Unique {
/// Create a new unique id.
pub fn new(unique: isize) -> Self { pub fn new(unique: isize) -> Self {
Unique(unique) Unique(unique)
} }
/// Increment the available unique id. This is used during
/// string interning to get the next available unique id.
pub fn increment(&mut self) { pub fn increment(&mut self) {
self.0 += 1; self.0 += 1;
} }
@ -90,12 +107,18 @@ impl Display for Unique {
} }
} }
/// Similar to `Name` but for Debruijn indices.
/// `Name` is replaced by `NamedDebruijn` when converting
/// program to it's debruijn form.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct NamedDeBruijn { pub struct NamedDeBruijn {
pub text: String, pub text: String,
pub index: DeBruijn, pub index: DeBruijn,
} }
/// This is useful for decoding a on chain program into debruijn form.
/// It allows for injecting fake textual names while also using Debruijn for decoding
/// without having to loop through twice.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct FakeNamedDeBruijn(NamedDeBruijn); pub struct FakeNamedDeBruijn(NamedDeBruijn);
@ -123,10 +146,12 @@ impl From<NamedDeBruijn> for FakeNamedDeBruijn {
} }
} }
/// Represents a debruijn index.
#[derive(Debug, Clone, PartialEq, Copy)] #[derive(Debug, Clone, PartialEq, Copy)]
pub struct DeBruijn(usize); pub struct DeBruijn(usize);
impl DeBruijn { impl DeBruijn {
/// Create a new debruijn index.
pub fn new(index: usize) -> Self { pub fn new(index: usize) -> Self {
DeBruijn(index) DeBruijn(index)
} }
@ -153,12 +178,15 @@ impl From<NamedDeBruijn> for DeBruijn {
impl From<DeBruijn> for NamedDeBruijn { impl From<DeBruijn> for NamedDeBruijn {
fn from(index: DeBruijn) -> Self { fn from(index: DeBruijn) -> Self {
NamedDeBruijn { NamedDeBruijn {
// Inject fake name. We got `i` from the Plutus code base.
text: String::from("i"), text: String::from("i"),
index, index,
} }
} }
} }
/// Convert a Parsed `Program` to a `Program` in `NamedDebruijn` form.
/// This checks for any Free Uniques in the `Program` and returns an error if found.
impl TryFrom<Program<Name>> for Program<NamedDeBruijn> { impl TryFrom<Program<Name>> for Program<NamedDeBruijn> {
type Error = debruijn::Error; type Error = debruijn::Error;
@ -170,6 +198,8 @@ impl TryFrom<Program<Name>> for Program<NamedDeBruijn> {
} }
} }
/// Convert a Parsed `Term` to a `Term` in `NamedDebruijn` form.
/// This checks for any Free Uniques in the `Term` and returns an error if found.
impl TryFrom<Term<Name>> for Term<NamedDeBruijn> { impl TryFrom<Term<Name>> for Term<NamedDeBruijn> {
type Error = debruijn::Error; type Error = debruijn::Error;
@ -182,6 +212,8 @@ impl TryFrom<Term<Name>> for Term<NamedDeBruijn> {
} }
} }
/// Convert a Parsed `Program` to a `Program` in `Debruijn` form.
/// This checks for any Free Uniques in the `Program` and returns an error if found.
impl TryFrom<Program<Name>> for Program<DeBruijn> { impl TryFrom<Program<Name>> for Program<DeBruijn> {
type Error = debruijn::Error; type Error = debruijn::Error;
@ -193,6 +225,8 @@ impl TryFrom<Program<Name>> for Program<DeBruijn> {
} }
} }
/// Convert a Parsed `Term` to a `Term` in `Debruijn` form.
/// This checks for any Free Uniques in the `Program` and returns an error if found.
impl TryFrom<Term<Name>> for Term<DeBruijn> { impl TryFrom<Term<Name>> for Term<DeBruijn> {
type Error = debruijn::Error; type Error = debruijn::Error;

View File

@ -1,6 +1,7 @@
use flat::de; use flat::de;
use strum_macros::EnumString; use strum_macros::EnumString;
/// All the possible builtin functions in Untyped Plutus Core.
#[repr(u8)] #[repr(u8)]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(Debug, Clone, EnumString, PartialEq, Copy)] #[derive(Debug, Clone, EnumString, PartialEq, Copy)]

View File

@ -10,11 +10,15 @@ use peg::{error::ParseError, str::LineCol};
mod interner; mod interner;
/// Parse a `Program` from a str.
pub fn program(src: &str) -> Result<Program<Name>, ParseError<LineCol>> { pub fn program(src: &str) -> Result<Program<Name>, ParseError<LineCol>> {
// initialize the string interner to get unique name
let mut interner = Interner::new(); let mut interner = Interner::new();
// run the generated parser
let mut program = uplc::program(src)?; let mut program = uplc::program(src)?;
// assign proper unique ids in place
interner.program(&mut program); interner.program(&mut program);
Ok(program) Ok(program)

View File

@ -1,4 +1,4 @@
// e2e encoding/decoding tests /// e2e encoding/decoding tests
use crate::{ use crate::{
ast::{DeBruijn, Program}, ast::{DeBruijn, Program},
parser, parser,