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::{
|
use crate::{
|
||||||
builtins::DefaultFunction,
|
builtins::DefaultFunction,
|
||||||
debruijn::{self, Converter},
|
debruijn::{self, Converter},
|
||||||
|
@ -28,6 +8,24 @@ use crate::{
|
||||||
Machine,
|
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.
|
/// This represents a program in Untyped Plutus Core.
|
||||||
/// A program contains a version tuple and a term.
|
/// A program contains a version tuple and a term.
|
||||||
|
@ -239,6 +237,61 @@ pub enum Constant {
|
||||||
Data(PlutusData),
|
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)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
Bool,
|
Bool,
|
||||||
|
|
|
@ -2,13 +2,14 @@ use crate::{
|
||||||
ast::{Constant, Name, Term, Type},
|
ast::{Constant, Name, Term, Type},
|
||||||
builtins::DefaultFunction,
|
builtins::DefaultFunction,
|
||||||
};
|
};
|
||||||
|
use pallas_primitives::alonzo::PlutusData;
|
||||||
|
|
||||||
pub const CONSTR_FIELDS_EXPOSER: &str = "__constr_fields_exposer";
|
pub const CONSTR_FIELDS_EXPOSER: &str = "__constr_fields_exposer";
|
||||||
pub const CONSTR_INDEX_EXPOSER: &str = "__constr_index_exposer";
|
pub const CONSTR_INDEX_EXPOSER: &str = "__constr_index_exposer";
|
||||||
pub const CONSTR_GET_FIELD: &str = "__constr_get_field";
|
pub const CONSTR_GET_FIELD: &str = "__constr_get_field";
|
||||||
pub const EXPECT_ON_LIST: &str = "__expect_on_list";
|
pub const EXPECT_ON_LIST: &str = "__expect_on_list";
|
||||||
|
|
||||||
impl Term<Name> {
|
impl<T> Term<T> {
|
||||||
pub fn apply(self, arg: Self) -> Self {
|
pub fn apply(self, arg: Self) -> Self {
|
||||||
Term::Apply {
|
Term::Apply {
|
||||||
function: self.into(),
|
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 {
|
pub fn force(self) -> Self {
|
||||||
Term::Force(self.into())
|
Term::Force(self.into())
|
||||||
}
|
}
|
||||||
|
@ -31,10 +25,6 @@ impl Term<Name> {
|
||||||
Term::Delay(self.into())
|
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 {
|
pub fn integer(i: num_bigint::BigInt) -> Self {
|
||||||
Term::Constant(Constant::Integer(i).into())
|
Term::Constant(Constant::Integer(i).into())
|
||||||
}
|
}
|
||||||
|
@ -55,6 +45,10 @@ impl Term<Name> {
|
||||||
Term::Constant(Constant::Unit.into())
|
Term::Constant(Constant::Unit.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn data(d: PlutusData) -> Self {
|
||||||
|
Term::Constant(Constant::Data(d).into())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn empty_list() -> Self {
|
pub fn empty_list() -> Self {
|
||||||
Term::Constant(Constant::ProtoList(Type::Data, vec![]).into())
|
Term::Constant(Constant::ProtoList(Type::Data, vec![]).into())
|
||||||
}
|
}
|
||||||
|
@ -204,7 +198,7 @@ impl Term<Name> {
|
||||||
.force()
|
.force()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trace(self, msg_term: Term<Name>) -> Self {
|
pub fn trace(self, msg_term: Self) -> Self {
|
||||||
Term::Builtin(DefaultFunction::Trace)
|
Term::Builtin(DefaultFunction::Trace)
|
||||||
.force()
|
.force()
|
||||||
.apply(msg_term)
|
.apply(msg_term)
|
||||||
|
@ -212,41 +206,34 @@ impl Term<Name> {
|
||||||
.force()
|
.force()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assert_on_list(self) -> Term<Name> {
|
pub fn final_wrapper(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),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn final_wrapper(self: Term<Name>) -> Term<Name> {
|
|
||||||
self.delayed_if_else(Term::unit(), Term::Error)
|
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(
|
self.lambda(CONSTR_FIELDS_EXPOSER.to_string()).apply(
|
||||||
Term::snd_pair()
|
Term::snd_pair()
|
||||||
.apply(Term::unconstr_data().apply(Term::var("__constr_var".to_string())))
|
.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(
|
self.lambda(CONSTR_INDEX_EXPOSER.to_string()).apply(
|
||||||
Term::fst_pair()
|
Term::fst_pair()
|
||||||
.apply(Term::unconstr_data().apply(Term::var("__constr_var".to_string())))
|
.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())
|
self.lambda(CONSTR_GET_FIELD.to_string())
|
||||||
.apply(
|
.apply(
|
||||||
Term::var(CONSTR_GET_FIELD.to_string())
|
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> {
|
pub fn assert_on_list(self) -> Self {
|
||||||
let mut term = self;
|
self.lambda(EXPECT_ON_LIST.to_string())
|
||||||
|
.apply(
|
||||||
for _ in 0..repeat {
|
Term::var(EXPECT_ON_LIST.to_string()).apply(Term::var(EXPECT_ON_LIST.to_string())),
|
||||||
term = Term::tail_list().apply(term);
|
)
|
||||||
}
|
.lambda(EXPECT_ON_LIST.to_string())
|
||||||
|
.apply(
|
||||||
term
|
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