Rework parameter validation to work from 'Constant' instead of 'Term'
This simplifies the code and makes it more efficient as we no longer need to wrap and unwrap constant terms constantly.
This commit is contained in:
parent
d58ef1a079
commit
7d6612b108
|
@ -6,7 +6,7 @@ use aiken_lang::ast::Span;
|
|||
use miette::{Diagnostic, NamedSource};
|
||||
use owo_colors::{OwoColorize, Stream::Stdout};
|
||||
use std::fmt::Debug;
|
||||
use uplc::ast::{DeBruijn, Term};
|
||||
use uplc::ast::Constant;
|
||||
|
||||
#[derive(Debug, thiserror::Error, Diagnostic)]
|
||||
pub enum Error {
|
||||
|
@ -48,12 +48,12 @@ pub enum Error {
|
|||
))]
|
||||
ParameterizedValidator { n: usize },
|
||||
|
||||
#[error("I failed to infer what should be the schema of a given parameter to apply.")]
|
||||
#[error("I stumble upon something else than a constant when I expected one.")]
|
||||
#[diagnostic(code("aiken:blueprint::apply::malformed::argument"))]
|
||||
#[diagnostic(help(
|
||||
"I couldn't figure out the schema corresponding to a term you've given. Here's a possible hint about why I failed: {hint}"
|
||||
"Parameters applied to blueprints must be constant; they cannot be lambdas or delayed terms."
|
||||
))]
|
||||
UnableToInferArgumentSchema { hint: String },
|
||||
NonConstantParameter,
|
||||
|
||||
#[error("I couldn't find a definition corresponding to a reference.")]
|
||||
#[diagnostic(code("aiken::blueprint::apply::unknown::reference"))]
|
||||
|
@ -70,10 +70,7 @@ pub enum Error {
|
|||
serde_json::to_string_pretty(&schema).unwrap().if_supports_color(Stdout, |s| s.green()),
|
||||
term.to_pretty().if_supports_color(Stdout, |s| s.red()),
|
||||
))]
|
||||
SchemaMismatch {
|
||||
schema: Schema,
|
||||
term: Term<DeBruijn>,
|
||||
},
|
||||
SchemaMismatch { schema: Schema, term: Constant },
|
||||
|
||||
#[error(
|
||||
"I discovered a discrepancy of elements between a given tuple and its declared schema."
|
||||
|
|
|
@ -3,7 +3,7 @@ use super::{
|
|||
error::Error,
|
||||
schema::{Annotated, Constructor, Data, Declaration, Items, Schema},
|
||||
};
|
||||
use std::{iter, ops::Deref, rc::Rc};
|
||||
use std::{iter, ops::Deref};
|
||||
use uplc::{
|
||||
ast::{Constant, Data as UplcData, DeBruijn, Term},
|
||||
PlutusData,
|
||||
|
@ -17,8 +17,6 @@ pub struct Parameter {
|
|||
pub schema: Reference,
|
||||
}
|
||||
|
||||
type Instance = Term<DeBruijn>;
|
||||
|
||||
impl From<Reference> for Parameter {
|
||||
fn from(schema: Reference) -> Parameter {
|
||||
Parameter {
|
||||
|
@ -32,7 +30,7 @@ impl Parameter {
|
|||
pub fn validate(
|
||||
&self,
|
||||
definitions: &Definitions<Annotated<Schema>>,
|
||||
term: &Instance,
|
||||
term: &Term<DeBruijn>,
|
||||
) -> Result<(), Error> {
|
||||
let schema = &definitions
|
||||
.lookup(&self.schema)
|
||||
|
@ -44,14 +42,18 @@ impl Parameter {
|
|||
})?
|
||||
.annotated;
|
||||
|
||||
validate_schema(schema, definitions, term)
|
||||
if let Term::Constant(constant) = term {
|
||||
validate_schema(schema, definitions, constant)
|
||||
} else {
|
||||
Err(Error::NonConstantParameter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_schema(
|
||||
schema: &Schema,
|
||||
definitions: &Definitions<Annotated<Schema>>,
|
||||
term: &Instance,
|
||||
term: &Constant,
|
||||
) -> Result<(), Error> {
|
||||
match schema {
|
||||
Schema::Data(data) => validate_data(data, definitions, term),
|
||||
|
@ -135,7 +137,7 @@ fn validate_schema(
|
|||
fn validate_data(
|
||||
data: &Data,
|
||||
definitions: &Definitions<Annotated<Schema>>,
|
||||
term: &Instance,
|
||||
term: &Constant,
|
||||
) -> Result<(), Error> {
|
||||
match data {
|
||||
Data::Opaque => expect_data(term),
|
||||
|
@ -267,12 +269,10 @@ fn validate_data(
|
|||
}
|
||||
}
|
||||
|
||||
fn expect_data(term: &Instance) -> Result<(), Error> {
|
||||
if let Term::Constant(constant) = term {
|
||||
if matches!(constant.deref(), Constant::Data(..)) {
|
||||
fn expect_data(term: &Constant) -> Result<(), Error> {
|
||||
if matches!(term, Constant::Data(..)) {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
Err(Error::SchemaMismatch {
|
||||
schema: Schema::Data(Data::Opaque),
|
||||
|
@ -280,14 +280,12 @@ fn expect_data(term: &Instance) -> Result<(), Error> {
|
|||
})
|
||||
}
|
||||
|
||||
fn expect_data_integer(term: &Instance) -> Result<(), Error> {
|
||||
if let Term::Constant(constant) = term {
|
||||
if let Constant::Data(data) = constant.deref() {
|
||||
fn expect_data_integer(term: &Constant) -> Result<(), Error> {
|
||||
if let Constant::Data(data) = term {
|
||||
if matches!(data, PlutusData::BigInt(..)) {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(Error::SchemaMismatch {
|
||||
schema: Schema::Data(Data::Integer),
|
||||
|
@ -295,14 +293,12 @@ fn expect_data_integer(term: &Instance) -> Result<(), Error> {
|
|||
})
|
||||
}
|
||||
|
||||
fn expect_data_bytes(term: &Instance) -> Result<(), Error> {
|
||||
if let Term::Constant(constant) = term {
|
||||
if let Constant::Data(data) = constant.deref() {
|
||||
fn expect_data_bytes(term: &Constant) -> Result<(), Error> {
|
||||
if let Constant::Data(data) = term {
|
||||
if matches!(data, PlutusData::BoundedBytes(..)) {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(Error::SchemaMismatch {
|
||||
schema: Schema::Data(Data::Bytes),
|
||||
|
@ -310,15 +306,13 @@ fn expect_data_bytes(term: &Instance) -> Result<(), Error> {
|
|||
})
|
||||
}
|
||||
|
||||
fn expect_data_list(term: &Instance) -> Result<Vec<Instance>, Error> {
|
||||
if let Term::Constant(constant) = term {
|
||||
if let Constant::Data(PlutusData::Array(elems)) = constant.deref() {
|
||||
fn expect_data_list(term: &Constant) -> Result<Vec<Constant>, Error> {
|
||||
if let Constant::Data(PlutusData::Array(elems)) = term {
|
||||
return Ok(elems
|
||||
.iter()
|
||||
.map(|elem| Term::Constant(Rc::new(Constant::Data(elem.to_owned()))))
|
||||
.map(|elem| Constant::Data(elem.to_owned()))
|
||||
.collect());
|
||||
}
|
||||
}
|
||||
|
||||
let inner_schema = Items::One(Declaration::Inline(Box::new(Data::Opaque)));
|
||||
|
||||
|
@ -328,20 +322,13 @@ fn expect_data_list(term: &Instance) -> Result<Vec<Instance>, Error> {
|
|||
})
|
||||
}
|
||||
|
||||
fn expect_data_map(term: &Instance) -> Result<Vec<(Instance, Instance)>, Error> {
|
||||
if let Term::Constant(constant) = term {
|
||||
if let Constant::Data(PlutusData::Map(pairs)) = constant.deref() {
|
||||
fn expect_data_map(term: &Constant) -> Result<Vec<(Constant, Constant)>, Error> {
|
||||
if let Constant::Data(PlutusData::Map(pairs)) = term {
|
||||
return Ok(pairs
|
||||
.iter()
|
||||
.map(|(k, v)| {
|
||||
(
|
||||
Term::Constant(Rc::new(Constant::Data(k.to_owned()))),
|
||||
Term::Constant(Rc::new(Constant::Data(v.to_owned()))),
|
||||
)
|
||||
})
|
||||
.map(|(k, v)| (Constant::Data(k.to_owned()), Constant::Data(v.to_owned())))
|
||||
.collect());
|
||||
}
|
||||
}
|
||||
|
||||
let key_schema = Declaration::Inline(Box::new(Data::Opaque));
|
||||
let value_schema = Declaration::Inline(Box::new(Data::Opaque));
|
||||
|
@ -352,21 +339,18 @@ fn expect_data_map(term: &Instance) -> Result<Vec<(Instance, Instance)>, Error>
|
|||
})
|
||||
}
|
||||
|
||||
fn expect_data_constr(term: &Instance, index: usize) -> Result<Vec<Instance>, Error> {
|
||||
if let Term::Constant(constant) = term {
|
||||
if let Constant::Data(PlutusData::Constr(constr)) = constant.deref() {
|
||||
fn expect_data_constr(term: &Constant, index: usize) -> Result<Vec<Constant>, Error> {
|
||||
if let Constant::Data(PlutusData::Constr(constr)) = term {
|
||||
if let PlutusData::Constr(expected) = UplcData::constr(index as u64, vec![]) {
|
||||
if expected.tag == constr.tag && expected.any_constructor == constr.any_constructor
|
||||
{
|
||||
if expected.tag == constr.tag && expected.any_constructor == constr.any_constructor {
|
||||
return Ok(constr
|
||||
.fields
|
||||
.iter()
|
||||
.map(|field| Term::Constant(Rc::new(Constant::Data(field.to_owned()))))
|
||||
.map(|field| Constant::Data(field.to_owned()))
|
||||
.collect());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(Error::SchemaMismatch {
|
||||
schema: Schema::Data(Data::AnyOf(vec![Constructor {
|
||||
|
@ -378,12 +362,10 @@ fn expect_data_constr(term: &Instance, index: usize) -> Result<Vec<Instance>, Er
|
|||
})
|
||||
}
|
||||
|
||||
fn expect_unit(term: &Instance) -> Result<(), Error> {
|
||||
if let Term::Constant(constant) = term {
|
||||
if matches!(constant.deref(), Constant::Unit) {
|
||||
fn expect_unit(term: &Constant) -> Result<(), Error> {
|
||||
if matches!(term, Constant::Unit) {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
Err(Error::SchemaMismatch {
|
||||
schema: Schema::Unit,
|
||||
|
@ -391,12 +373,10 @@ fn expect_unit(term: &Instance) -> Result<(), Error> {
|
|||
})
|
||||
}
|
||||
|
||||
fn expect_integer(term: &Instance) -> Result<(), Error> {
|
||||
if let Term::Constant(constant) = term {
|
||||
if matches!(constant.deref(), Constant::Integer(..)) {
|
||||
fn expect_integer(term: &Constant) -> Result<(), Error> {
|
||||
if matches!(term, Constant::Integer(..)) {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
Err(Error::SchemaMismatch {
|
||||
schema: Schema::Integer,
|
||||
|
@ -404,12 +384,10 @@ fn expect_integer(term: &Instance) -> Result<(), Error> {
|
|||
})
|
||||
}
|
||||
|
||||
fn expect_bytes(term: &Instance) -> Result<(), Error> {
|
||||
if let Term::Constant(constant) = term {
|
||||
if matches!(constant.deref(), Constant::ByteString(..)) {
|
||||
fn expect_bytes(term: &Constant) -> Result<(), Error> {
|
||||
if matches!(term, Constant::ByteString(..)) {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
Err(Error::SchemaMismatch {
|
||||
schema: Schema::Bytes,
|
||||
|
@ -417,12 +395,10 @@ fn expect_bytes(term: &Instance) -> Result<(), Error> {
|
|||
})
|
||||
}
|
||||
|
||||
fn expect_string(term: &Instance) -> Result<(), Error> {
|
||||
if let Term::Constant(constant) = term {
|
||||
if matches!(constant.deref(), Constant::String(..)) {
|
||||
fn expect_string(term: &Constant) -> Result<(), Error> {
|
||||
if matches!(term, Constant::String(..)) {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
Err(Error::SchemaMismatch {
|
||||
schema: Schema::String,
|
||||
|
@ -430,12 +406,10 @@ fn expect_string(term: &Instance) -> Result<(), Error> {
|
|||
})
|
||||
}
|
||||
|
||||
fn expect_boolean(term: &Instance) -> Result<(), Error> {
|
||||
if let Term::Constant(constant) = term {
|
||||
if matches!(constant.deref(), Constant::Bool(..)) {
|
||||
fn expect_boolean(term: &Constant) -> Result<(), Error> {
|
||||
if matches!(term, Constant::Bool(..)) {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
Err(Error::SchemaMismatch {
|
||||
schema: Schema::Boolean,
|
||||
|
@ -443,11 +417,9 @@ fn expect_boolean(term: &Instance) -> Result<(), Error> {
|
|||
})
|
||||
}
|
||||
|
||||
fn expect_pair(term: &Instance) -> Result<(Instance, Instance), Error> {
|
||||
if let Term::Constant(constant) = term {
|
||||
if let Constant::ProtoPair(_, _, left, right) = constant.deref() {
|
||||
return Ok((Term::Constant(left.clone()), Term::Constant(right.clone())));
|
||||
}
|
||||
fn expect_pair(term: &Constant) -> Result<(Constant, Constant), Error> {
|
||||
if let Constant::ProtoPair(_, _, left, right) = term {
|
||||
return Ok((left.deref().clone(), right.deref().clone()));
|
||||
}
|
||||
|
||||
let left_schema = Declaration::Inline(Box::new(Schema::Data(Data::Opaque)));
|
||||
|
@ -459,14 +431,9 @@ fn expect_pair(term: &Instance) -> Result<(Instance, Instance), Error> {
|
|||
})
|
||||
}
|
||||
|
||||
fn expect_list(term: &Instance) -> Result<Vec<Instance>, Error> {
|
||||
if let Term::Constant(constant) = term {
|
||||
if let Constant::ProtoList(_, elems) = constant.deref() {
|
||||
return Ok(elems
|
||||
.iter()
|
||||
.map(|elem| Term::Constant(Rc::new(elem.to_owned())))
|
||||
.collect());
|
||||
}
|
||||
fn expect_list(term: &Constant) -> Result<Vec<Constant>, Error> {
|
||||
if let Constant::ProtoList(_, elems) = term {
|
||||
return Ok(elems.to_owned());
|
||||
}
|
||||
|
||||
let inner_schema = Items::One(Declaration::Inline(Box::new(Schema::Data(Data::Opaque))));
|
||||
|
|
Loading…
Reference in New Issue