Implement 'reify_constant' and rename reify to 'reify_data'
Both fullfill similar goal, but reify_constant sits one level above.
This commit is contained in:
parent
8ffa68d2f0
commit
59996850c1
|
@ -1,9 +1,9 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{
|
ast::{
|
||||||
self, Annotation, Arg, AssignmentKind, BinOp, ByteArrayFormatPreference, CallArg, Curve,
|
self, Annotation, Arg, AssignmentKind, BinOp, Bls12_381Point, ByteArrayFormatPreference,
|
||||||
DataType, DataTypeKey, DefinitionLocation, IfBranch, Located, LogicalOpChainKind,
|
CallArg, Curve, DataType, DataTypeKey, DefinitionLocation, IfBranch, Located,
|
||||||
ParsedCallArg, Pattern, RecordConstructorArg, RecordUpdateSpread, Span, TraceKind,
|
LogicalOpChainKind, ParsedCallArg, Pattern, RecordConstructorArg, RecordUpdateSpread, Span,
|
||||||
TypedClause, TypedDataType, TypedRecordUpdateArg, UnOp, UntypedClause,
|
TraceKind, TypedClause, TypedDataType, TypedRecordUpdateArg, UnOp, UntypedClause,
|
||||||
UntypedRecordUpdateArg,
|
UntypedRecordUpdateArg,
|
||||||
},
|
},
|
||||||
builtins::void,
|
builtins::void,
|
||||||
|
@ -16,7 +16,7 @@ use crate::{
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use pallas::ledger::primitives::alonzo::{Constr, PlutusData};
|
use pallas::ledger::primitives::alonzo::{Constr, PlutusData};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use uplc::{machine::value::from_pallas_bigint, KeyValuePairs};
|
use uplc::{ast::Data, machine::value::from_pallas_bigint, KeyValuePairs};
|
||||||
use vec1::Vec1;
|
use vec1::Vec1;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
@ -578,20 +578,151 @@ pub const DEFAULT_TODO_STR: &str = "aiken::todo";
|
||||||
pub const DEFAULT_ERROR_STR: &str = "aiken::error";
|
pub const DEFAULT_ERROR_STR: &str = "aiken::error";
|
||||||
|
|
||||||
impl UntypedExpr {
|
impl UntypedExpr {
|
||||||
|
pub fn reify_constant(
|
||||||
|
data_types: &IndexMap<&DataTypeKey, &TypedDataType>,
|
||||||
|
cst: uplc::ast::Constant,
|
||||||
|
tipo: &Type,
|
||||||
|
) -> Result<Self, String> {
|
||||||
|
if let Type::Var { tipo } = tipo {
|
||||||
|
if let TypeVar::Link { tipo } = &*tipo.borrow() {
|
||||||
|
return UntypedExpr::reify_constant(data_types, cst, tipo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match cst {
|
||||||
|
uplc::ast::Constant::Data(data) => UntypedExpr::reify_data(data_types, data, tipo),
|
||||||
|
|
||||||
|
uplc::ast::Constant::Integer(i) => {
|
||||||
|
UntypedExpr::reify_data(data_types, Data::integer(i), tipo)
|
||||||
|
}
|
||||||
|
|
||||||
|
uplc::ast::Constant::ByteString(bytes) => {
|
||||||
|
UntypedExpr::reify_data(data_types, Data::bytestring(bytes), tipo)
|
||||||
|
}
|
||||||
|
|
||||||
|
uplc::ast::Constant::ProtoList(_, args) => match tipo {
|
||||||
|
Type::App {
|
||||||
|
module,
|
||||||
|
name,
|
||||||
|
args: type_args,
|
||||||
|
..
|
||||||
|
} if module.is_empty() && name.as_str() == "List" => {
|
||||||
|
if let [inner] = &type_args[..] {
|
||||||
|
Ok(UntypedExpr::List {
|
||||||
|
location: Span::empty(),
|
||||||
|
elements: args
|
||||||
|
.into_iter()
|
||||||
|
.map(|arg| UntypedExpr::reify_constant(data_types, arg, inner))
|
||||||
|
.collect::<Result<Vec<_>, _>>()?,
|
||||||
|
tail: None,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(
|
||||||
|
"invalid List type annotation: the list has multiple type-parameters."
|
||||||
|
.to_string(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Type::Tuple { elems } => Ok(UntypedExpr::Tuple {
|
||||||
|
location: Span::empty(),
|
||||||
|
elems: args
|
||||||
|
.into_iter()
|
||||||
|
.zip(elems)
|
||||||
|
.map(|(arg, arg_type)| {
|
||||||
|
UntypedExpr::reify_constant(data_types, arg, arg_type)
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>, _>>()?,
|
||||||
|
}),
|
||||||
|
_ => Err(format!(
|
||||||
|
"invalid type annotation. expected List but got: {tipo:?}"
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
|
||||||
|
uplc::ast::Constant::ProtoPair(_, _, left, right) => match tipo {
|
||||||
|
Type::Tuple { elems } => Ok(UntypedExpr::Tuple {
|
||||||
|
location: Span::empty(),
|
||||||
|
elems: [left.as_ref(), right.as_ref()]
|
||||||
|
.into_iter()
|
||||||
|
.zip(elems)
|
||||||
|
.map(|(arg, arg_type)| {
|
||||||
|
UntypedExpr::reify_constant(data_types, arg.to_owned(), arg_type)
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>, _>>()?,
|
||||||
|
}),
|
||||||
|
_ => Err(format!(
|
||||||
|
"invalid type annotation. expected Tuple but got: {tipo:?}"
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
|
||||||
|
uplc::ast::Constant::Unit => Ok(UntypedExpr::Var {
|
||||||
|
location: Span::empty(),
|
||||||
|
name: "Void".to_string(),
|
||||||
|
}),
|
||||||
|
|
||||||
|
uplc::ast::Constant::Bool(is_true) => Ok(UntypedExpr::Var {
|
||||||
|
location: Span::empty(),
|
||||||
|
name: if is_true { "True" } else { "False" }.to_string(),
|
||||||
|
}),
|
||||||
|
|
||||||
|
uplc::ast::Constant::String(value) => Ok(UntypedExpr::String {
|
||||||
|
location: Span::empty(),
|
||||||
|
value,
|
||||||
|
}),
|
||||||
|
|
||||||
|
uplc::ast::Constant::Bls12_381G1Element(pt) => Ok(UntypedExpr::CurvePoint {
|
||||||
|
location: Span::empty(),
|
||||||
|
point: Curve::Bls12_381(Bls12_381Point::G1(*pt)).into(),
|
||||||
|
preferred_format: ByteArrayFormatPreference::HexadecimalString,
|
||||||
|
}),
|
||||||
|
|
||||||
|
uplc::ast::Constant::Bls12_381G2Element(pt) => Ok(UntypedExpr::CurvePoint {
|
||||||
|
location: Span::empty(),
|
||||||
|
point: Curve::Bls12_381(Bls12_381Point::G2(*pt)).into(),
|
||||||
|
preferred_format: ByteArrayFormatPreference::HexadecimalString,
|
||||||
|
}),
|
||||||
|
|
||||||
|
uplc::ast::Constant::Bls12_381MlResult(ml) => {
|
||||||
|
let mut bytes = Vec::new();
|
||||||
|
|
||||||
|
bytes.extend((*ml).to_bendian());
|
||||||
|
|
||||||
|
// NOTE: We don't actually have a syntax for representing MillerLoop results, so we
|
||||||
|
// just fake it as a constructor with a bytearray. Note also that the bytearray is
|
||||||
|
// *large*.
|
||||||
|
Ok(UntypedExpr::Call {
|
||||||
|
location: Span::empty(),
|
||||||
|
arguments: vec![CallArg {
|
||||||
|
label: None,
|
||||||
|
location: Span::empty(),
|
||||||
|
value: UntypedExpr::ByteArray {
|
||||||
|
location: Span::empty(),
|
||||||
|
bytes,
|
||||||
|
preferred_format: ByteArrayFormatPreference::HexadecimalString,
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
fun: Box::new(UntypedExpr::Var {
|
||||||
|
name: "MillerLoopResult".to_string(),
|
||||||
|
location: Span::empty(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Reify some opaque 'PlutusData' into an 'UntypedExpr', using a Type annotation. We also need
|
// Reify some opaque 'PlutusData' into an 'UntypedExpr', using a Type annotation. We also need
|
||||||
// an extra map to lookup record & enum constructor's names as they're completely erased when
|
// an extra map to lookup record & enum constructor's names as they're completely erased when
|
||||||
// in their PlutusData form, and the Type annotation only contains type name.
|
// in their PlutusData form, and the Type annotation only contains type name.
|
||||||
//
|
//
|
||||||
// The function performs some sanity check to ensure that the type does indeed somewhat
|
// The function performs some sanity check to ensure that the type does indeed somewhat
|
||||||
// correspond to the data being given.
|
// correspond to the data being given.
|
||||||
pub fn reify(
|
pub fn reify_data(
|
||||||
data_types: &IndexMap<&DataTypeKey, &TypedDataType>,
|
data_types: &IndexMap<&DataTypeKey, &TypedDataType>,
|
||||||
data: PlutusData,
|
data: PlutusData,
|
||||||
tipo: &Type,
|
tipo: &Type,
|
||||||
) -> Result<Self, String> {
|
) -> Result<Self, String> {
|
||||||
if let Type::Var { tipo } = tipo {
|
if let Type::Var { tipo } = tipo {
|
||||||
if let TypeVar::Link { tipo } = &*tipo.borrow() {
|
if let TypeVar::Link { tipo } = &*tipo.borrow() {
|
||||||
return UntypedExpr::reify(data_types, data, tipo);
|
return UntypedExpr::reify_data(data_types, data, tipo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -609,7 +740,7 @@ impl UntypedExpr {
|
||||||
|
|
||||||
let inner_type = convert_opaque_type(&tipo.clone().into(), data_types, false);
|
let inner_type = convert_opaque_type(&tipo.clone().into(), data_types, false);
|
||||||
|
|
||||||
let value = UntypedExpr::reify(data_types, data, &inner_type)?;
|
let value = UntypedExpr::reify_data(data_types, data, &inner_type)?;
|
||||||
|
|
||||||
return Ok(UntypedExpr::Call {
|
return Ok(UntypedExpr::Call {
|
||||||
location: Span::empty(),
|
location: Span::empty(),
|
||||||
|
@ -633,13 +764,14 @@ impl UntypedExpr {
|
||||||
},
|
},
|
||||||
value: from_pallas_bigint(i).to_string(),
|
value: from_pallas_bigint(i).to_string(),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
PlutusData::BoundedBytes(bytes) => Ok(UntypedExpr::ByteArray {
|
PlutusData::BoundedBytes(bytes) => Ok(UntypedExpr::ByteArray {
|
||||||
location: Span::empty(),
|
location: Span::empty(),
|
||||||
bytes: bytes.into(),
|
bytes: bytes.into(),
|
||||||
preferred_format: ByteArrayFormatPreference::HexadecimalString,
|
preferred_format: ByteArrayFormatPreference::HexadecimalString,
|
||||||
}),
|
}),
|
||||||
PlutusData::Array(args) => {
|
|
||||||
match tipo {
|
PlutusData::Array(args) => match tipo {
|
||||||
Type::App {
|
Type::App {
|
||||||
module,
|
module,
|
||||||
name,
|
name,
|
||||||
|
@ -651,12 +783,15 @@ impl UntypedExpr {
|
||||||
location: Span::empty(),
|
location: Span::empty(),
|
||||||
elements: args
|
elements: args
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|arg| UntypedExpr::reify(data_types, arg, inner))
|
.map(|arg| UntypedExpr::reify_data(data_types, arg, inner))
|
||||||
.collect::<Result<Vec<_>, _>>()?,
|
.collect::<Result<Vec<_>, _>>()?,
|
||||||
tail: None,
|
tail: None,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err("invalid List type annotation: the list has multiple type-parameters.".to_string())
|
Err(
|
||||||
|
"invalid List type annotation: the list has multiple type-parameters."
|
||||||
|
.to_string(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Type::Tuple { elems } => Ok(UntypedExpr::Tuple {
|
Type::Tuple { elems } => Ok(UntypedExpr::Tuple {
|
||||||
|
@ -664,14 +799,13 @@ impl UntypedExpr {
|
||||||
elems: args
|
elems: args
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.zip(elems)
|
.zip(elems)
|
||||||
.map(|(arg, arg_type)| UntypedExpr::reify(data_types, arg, arg_type))
|
.map(|(arg, arg_type)| UntypedExpr::reify_data(data_types, arg, arg_type))
|
||||||
.collect::<Result<Vec<_>, _>>()?,
|
.collect::<Result<Vec<_>, _>>()?,
|
||||||
}),
|
}),
|
||||||
_ => Err(format!(
|
_ => Err(format!(
|
||||||
"invalid type annotation. expected List but got: {tipo:?}"
|
"invalid type annotation. expected List but got: {tipo:?}"
|
||||||
)),
|
)),
|
||||||
}
|
},
|
||||||
}
|
|
||||||
|
|
||||||
PlutusData::Constr(Constr {
|
PlutusData::Constr(Constr {
|
||||||
tag,
|
tag,
|
||||||
|
@ -710,13 +844,13 @@ impl UntypedExpr {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
)| {
|
)| {
|
||||||
UntypedExpr::reify(data_types, field, tipo).map(|value| {
|
UntypedExpr::reify_data(data_types, field, tipo).map(
|
||||||
CallArg {
|
|value| CallArg {
|
||||||
label: label.clone(),
|
label: label.clone(),
|
||||||
location: Span::empty(),
|
location: Span::empty(),
|
||||||
value,
|
value,
|
||||||
}
|
},
|
||||||
})
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
@ -744,7 +878,7 @@ impl UntypedExpr {
|
||||||
KeyValuePairs::Indef(kvs) => kvs,
|
KeyValuePairs::Indef(kvs) => kvs,
|
||||||
};
|
};
|
||||||
|
|
||||||
UntypedExpr::reify(
|
UntypedExpr::reify_data(
|
||||||
data_types,
|
data_types,
|
||||||
PlutusData::Array(
|
PlutusData::Array(
|
||||||
kvs.into_iter()
|
kvs.into_iter()
|
||||||
|
|
|
@ -794,7 +794,11 @@ impl PropertyTestResult<PlutusData> {
|
||||||
counterexample: match self.counterexample {
|
counterexample: match self.counterexample {
|
||||||
None => None,
|
None => None,
|
||||||
Some(counterexample) => Some(
|
Some(counterexample) => Some(
|
||||||
UntypedExpr::reify(data_types, counterexample, &self.test.fuzzer.type_info)
|
UntypedExpr::reify_data(
|
||||||
|
data_types,
|
||||||
|
counterexample,
|
||||||
|
&self.test.fuzzer.type_info,
|
||||||
|
)
|
||||||
.expect("Failed to reify counterexample?"),
|
.expect("Failed to reify counterexample?"),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
@ -1073,7 +1077,7 @@ mod test {
|
||||||
|
|
||||||
let reify = move |counterexample| {
|
let reify = move |counterexample| {
|
||||||
let data_type_refs = utils::indexmap::as_ref_values(&data_types);
|
let data_type_refs = utils::indexmap::as_ref_values(&data_types);
|
||||||
let expr = UntypedExpr::reify(&data_type_refs, counterexample, &type_info)
|
let expr = UntypedExpr::reify_data(&data_type_refs, counterexample, &type_info)
|
||||||
.expect("Failed to reify value.");
|
.expect("Failed to reify value.");
|
||||||
Formatter::new().expr(&expr, false).to_pretty_string(70)
|
Formatter::new().expr(&expr, false).to_pretty_string(70)
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue