Implement quick builder on PlutusData.
In the same spirit of the existing Term builder; I also added a `data` method to lift a `PlutusData` into a `Term<T>` and generalized a bit the builder to only require a `Term<Name>` when necessary and remain generic otherwise. The `PlutusData` builder could potentially be upstreamed to pallas diretly.
This commit is contained in:
parent
f311e048b7
commit
9033b44044
|
@ -1,23 +1,3 @@
|
|||
use std::{
|
||||
fmt::{self, Display},
|
||||
hash::{self, Hash},
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
use num_bigint::BigInt;
|
||||
use serde::{
|
||||
self,
|
||||
de::{self, Deserialize, Deserializer, MapAccess, Visitor},
|
||||
ser::{Serialize, SerializeStruct, Serializer},
|
||||
};
|
||||
|
||||
use pallas_addresses::{Network, ShelleyAddress, ShelleyDelegationPart, ShelleyPaymentPart};
|
||||
use pallas_primitives::{
|
||||
alonzo::PlutusData,
|
||||
babbage::{self as cardano, Language},
|
||||
};
|
||||
use pallas_traverse::ComputeHash;
|
||||
|
||||
use crate::{
|
||||
builtins::DefaultFunction,
|
||||
debruijn::{self, Converter},
|
||||
|
@ -28,6 +8,24 @@ use crate::{
|
|||
Machine,
|
||||
},
|
||||
};
|
||||
use num_bigint::BigInt;
|
||||
use num_traits::ToPrimitive;
|
||||
use pallas_addresses::{Network, ShelleyAddress, ShelleyDelegationPart, ShelleyPaymentPart};
|
||||
use pallas_primitives::{
|
||||
alonzo::{self as pallas, Constr, PlutusData},
|
||||
babbage::{self as cardano, Language},
|
||||
};
|
||||
use pallas_traverse::ComputeHash;
|
||||
use serde::{
|
||||
self,
|
||||
de::{self, Deserialize, Deserializer, MapAccess, Visitor},
|
||||
ser::{Serialize, SerializeStruct, Serializer},
|
||||
};
|
||||
use std::{
|
||||
fmt::{self, Display},
|
||||
hash::{self, Hash},
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
/// This represents a program in Untyped Plutus Core.
|
||||
/// A program contains a version tuple and a term.
|
||||
|
@ -239,6 +237,61 @@ pub enum Constant {
|
|||
Data(PlutusData),
|
||||
}
|
||||
|
||||
pub struct Data {}
|
||||
|
||||
// TODO: See about moving these builders upstream to Pallas?
|
||||
impl Data {
|
||||
pub fn integer(i: BigInt) -> PlutusData {
|
||||
match i.to_i64() {
|
||||
Some(i) => PlutusData::BigInt(pallas::BigInt::Int(i.into())),
|
||||
None => {
|
||||
let (sign, bytes) = i.to_bytes_be();
|
||||
match sign {
|
||||
num_bigint::Sign::Minus => {
|
||||
PlutusData::BigInt(pallas::BigInt::BigNInt(bytes.into()))
|
||||
}
|
||||
_ => PlutusData::BigInt(pallas::BigInt::BigUInt(bytes.into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bytestring(bytes: Vec<u8>) -> PlutusData {
|
||||
PlutusData::BoundedBytes(bytes.into())
|
||||
}
|
||||
|
||||
pub fn map(kvs: Vec<(PlutusData, PlutusData)>) -> PlutusData {
|
||||
PlutusData::Map(kvs.into())
|
||||
}
|
||||
|
||||
pub fn list(xs: Vec<PlutusData>) -> PlutusData {
|
||||
PlutusData::Array(xs)
|
||||
}
|
||||
|
||||
pub fn constr(ix: u64, fields: Vec<PlutusData>) -> PlutusData {
|
||||
// NOTE: see https://github.com/input-output-hk/plutus/blob/9538fc9829426b2ecb0628d352e2d7af96ec8204/plutus-core/plutus-core/src/PlutusCore/Data.hs#L139-L155
|
||||
if ix < 7 {
|
||||
PlutusData::Constr(Constr {
|
||||
tag: 121 + ix,
|
||||
any_constructor: None,
|
||||
fields,
|
||||
})
|
||||
} else if ix < 128 {
|
||||
PlutusData::Constr(Constr {
|
||||
tag: 1280 + ix - 7,
|
||||
any_constructor: None,
|
||||
fields,
|
||||
})
|
||||
} else {
|
||||
PlutusData::Constr(Constr {
|
||||
tag: 102,
|
||||
any_constructor: Some(ix),
|
||||
fields,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Type {
|
||||
Bool,
|
||||
|
|
|
@ -2,13 +2,14 @@ use crate::{
|
|||
ast::{Constant, Name, Term, Type},
|
||||
builtins::DefaultFunction,
|
||||
};
|
||||
use pallas_primitives::alonzo::PlutusData;
|
||||
|
||||
pub const CONSTR_FIELDS_EXPOSER: &str = "__constr_fields_exposer";
|
||||
pub const CONSTR_INDEX_EXPOSER: &str = "__constr_index_exposer";
|
||||
pub const CONSTR_GET_FIELD: &str = "__constr_get_field";
|
||||
pub const EXPECT_ON_LIST: &str = "__expect_on_list";
|
||||
|
||||
impl Term<Name> {
|
||||
impl<T> Term<T> {
|
||||
pub fn apply(self, arg: Self) -> Self {
|
||||
Term::Apply {
|
||||
function: self.into(),
|
||||
|
@ -16,13 +17,6 @@ impl Term<Name> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn lambda(self, parameter_name: impl ToString) -> Self {
|
||||
Term::Lambda {
|
||||
parameter_name: Name::text(parameter_name).into(),
|
||||
body: self.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn force(self) -> Self {
|
||||
Term::Force(self.into())
|
||||
}
|
||||
|
@ -31,10 +25,6 @@ impl Term<Name> {
|
|||
Term::Delay(self.into())
|
||||
}
|
||||
|
||||
pub fn var(name: impl ToString) -> Self {
|
||||
Term::Var(Name::text(name).into())
|
||||
}
|
||||
|
||||
pub fn integer(i: num_bigint::BigInt) -> Self {
|
||||
Term::Constant(Constant::Integer(i).into())
|
||||
}
|
||||
|
@ -55,6 +45,10 @@ impl Term<Name> {
|
|||
Term::Constant(Constant::Unit.into())
|
||||
}
|
||||
|
||||
pub fn data(d: PlutusData) -> Self {
|
||||
Term::Constant(Constant::Data(d).into())
|
||||
}
|
||||
|
||||
pub fn empty_list() -> Self {
|
||||
Term::Constant(Constant::ProtoList(Type::Data, vec![]).into())
|
||||
}
|
||||
|
@ -204,7 +198,7 @@ impl Term<Name> {
|
|||
.force()
|
||||
}
|
||||
|
||||
pub fn trace(self, msg_term: Term<Name>) -> Self {
|
||||
pub fn trace(self, msg_term: Self) -> Self {
|
||||
Term::Builtin(DefaultFunction::Trace)
|
||||
.force()
|
||||
.apply(msg_term)
|
||||
|
@ -212,41 +206,34 @@ impl Term<Name> {
|
|||
.force()
|
||||
}
|
||||
|
||||
pub fn assert_on_list(self) -> Term<Name> {
|
||||
self.lambda(EXPECT_ON_LIST.to_string())
|
||||
.apply(
|
||||
Term::var(EXPECT_ON_LIST.to_string()).apply(Term::var(EXPECT_ON_LIST.to_string())),
|
||||
)
|
||||
.lambda(EXPECT_ON_LIST.to_string())
|
||||
.apply(
|
||||
Term::var("__list_to_check".to_string())
|
||||
.delayed_choose_list(
|
||||
Term::unit(),
|
||||
Term::var("__check_with".to_string())
|
||||
.apply(
|
||||
Term::head_list().apply(Term::var("__list_to_check".to_string())),
|
||||
)
|
||||
.choose_unit(
|
||||
Term::var(EXPECT_ON_LIST.to_string())
|
||||
.apply(Term::var(EXPECT_ON_LIST.to_string()))
|
||||
.apply(
|
||||
Term::tail_list()
|
||||
.apply(Term::var("__list_to_check".to_string())),
|
||||
)
|
||||
.apply(Term::var("__check_with".to_string())),
|
||||
),
|
||||
)
|
||||
.lambda("__check_with".to_string())
|
||||
.lambda("__list_to_check".to_string())
|
||||
.lambda(EXPECT_ON_LIST),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn final_wrapper(self: Term<Name>) -> Term<Name> {
|
||||
pub fn final_wrapper(self) -> Self {
|
||||
self.delayed_if_else(Term::unit(), Term::Error)
|
||||
}
|
||||
|
||||
pub fn constr_fields_exposer(self: Term<Name>) -> Term<Name> {
|
||||
pub fn repeat_tail_list(self, repeat: usize) -> Self {
|
||||
let mut term = self;
|
||||
|
||||
for _ in 0..repeat {
|
||||
term = Term::tail_list().apply(term);
|
||||
}
|
||||
|
||||
term
|
||||
}
|
||||
}
|
||||
|
||||
impl Term<Name> {
|
||||
pub fn lambda(self, parameter_name: impl ToString) -> Self {
|
||||
Term::Lambda {
|
||||
parameter_name: Name::text(parameter_name).into(),
|
||||
body: self.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn var(name: impl ToString) -> Self {
|
||||
Term::Var(Name::text(name).into())
|
||||
}
|
||||
|
||||
pub fn constr_fields_exposer(self) -> Self {
|
||||
self.lambda(CONSTR_FIELDS_EXPOSER.to_string()).apply(
|
||||
Term::snd_pair()
|
||||
.apply(Term::unconstr_data().apply(Term::var("__constr_var".to_string())))
|
||||
|
@ -254,7 +241,7 @@ impl Term<Name> {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn constr_index_exposer(self: Term<Name>) -> Term<Name> {
|
||||
pub fn constr_index_exposer(self) -> Self {
|
||||
self.lambda(CONSTR_INDEX_EXPOSER.to_string()).apply(
|
||||
Term::fst_pair()
|
||||
.apply(Term::unconstr_data().apply(Term::var("__constr_var".to_string())))
|
||||
|
@ -262,7 +249,7 @@ impl Term<Name> {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn constr_get_field(self: Term<Name>) -> Term<Name> {
|
||||
pub fn constr_get_field(self) -> Self {
|
||||
self.lambda(CONSTR_GET_FIELD.to_string())
|
||||
.apply(
|
||||
Term::var(CONSTR_GET_FIELD.to_string())
|
||||
|
@ -298,13 +285,33 @@ impl Term<Name> {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn repeat_tail_list(self: Term<Name>, repeat: usize) -> Term<Name> {
|
||||
let mut term = self;
|
||||
|
||||
for _ in 0..repeat {
|
||||
term = Term::tail_list().apply(term);
|
||||
}
|
||||
|
||||
term
|
||||
pub fn assert_on_list(self) -> Self {
|
||||
self.lambda(EXPECT_ON_LIST.to_string())
|
||||
.apply(
|
||||
Term::var(EXPECT_ON_LIST.to_string()).apply(Term::var(EXPECT_ON_LIST.to_string())),
|
||||
)
|
||||
.lambda(EXPECT_ON_LIST.to_string())
|
||||
.apply(
|
||||
Term::var("__list_to_check".to_string())
|
||||
.delayed_choose_list(
|
||||
Term::unit(),
|
||||
Term::var("__check_with".to_string())
|
||||
.apply(
|
||||
Term::head_list().apply(Term::var("__list_to_check".to_string())),
|
||||
)
|
||||
.choose_unit(
|
||||
Term::var(EXPECT_ON_LIST.to_string())
|
||||
.apply(Term::var(EXPECT_ON_LIST.to_string()))
|
||||
.apply(
|
||||
Term::tail_list()
|
||||
.apply(Term::var("__list_to_check".to_string())),
|
||||
)
|
||||
.apply(Term::var("__check_with".to_string())),
|
||||
),
|
||||
)
|
||||
.lambda("__check_with".to_string())
|
||||
.lambda("__list_to_check".to_string())
|
||||
.lambda(EXPECT_ON_LIST),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue