Allow annotating Data for blueprint
This commit allows Data to be optionally annotated with a phantom-type. This doesn't change anything in codegen but we can now leverage this information to generate better blueprint schemas.
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
---
|
||||
source: crates/aiken-project/src/blueprint/validator.rs
|
||||
description: "Code:\n\npub type Foo {\n foo: Int\n}\n\nvalidator {\n fn annotated_data(datum: Data<Foo>, redeemer: Data, ctx: Void) {\n True\n }\n}\n"
|
||||
---
|
||||
{
|
||||
"title": "test_module.annotated_data",
|
||||
"datum": {
|
||||
"title": "datum",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/test_module~1Foo"
|
||||
}
|
||||
},
|
||||
"redeemer": {
|
||||
"title": "redeemer",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Data"
|
||||
}
|
||||
},
|
||||
"compiledCode": "5833010000323222253330044a22930a99802a491856616c696461746f722072657475726e65642066616c736500136565734ae701",
|
||||
"hash": "52a21f2b4f282074cb6c5aefef20d18c25f3657ca348c73875810c37",
|
||||
"definitions": {
|
||||
"Data": {
|
||||
"title": "Data",
|
||||
"description": "Any Plutus data."
|
||||
},
|
||||
"Int": {
|
||||
"dataType": "integer"
|
||||
},
|
||||
"test_module/Foo": {
|
||||
"title": "Foo",
|
||||
"anyOf": [
|
||||
{
|
||||
"title": "Foo",
|
||||
"dataType": "constructor",
|
||||
"index": 0,
|
||||
"fields": [
|
||||
{
|
||||
"title": "foo",
|
||||
"$ref": "#/definitions/Int"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,14 +5,15 @@ use super::{
|
||||
schema::{Annotated, Schema},
|
||||
};
|
||||
use crate::module::{CheckedModule, CheckedModules};
|
||||
use std::rc::Rc;
|
||||
|
||||
use aiken_lang::{
|
||||
ast::{TypedArg, TypedFunction, TypedValidator},
|
||||
ast::{Annotation, TypedArg, TypedFunction, TypedValidator},
|
||||
gen_uplc::CodeGenerator,
|
||||
tipo::Type,
|
||||
};
|
||||
use miette::NamedSource;
|
||||
use serde;
|
||||
use std::borrow::Borrow;
|
||||
use std::rc::Rc;
|
||||
use uplc::{
|
||||
ast::{Constant, DeBruijn, Program, Term},
|
||||
PlutusData,
|
||||
@@ -96,19 +97,23 @@ impl Validator {
|
||||
let parameters = params
|
||||
.iter()
|
||||
.map(|param| {
|
||||
Annotated::from_type(modules.into(), ¶m.tipo, &mut definitions)
|
||||
.map(|schema| Parameter {
|
||||
title: Some(param.arg_name.get_label()),
|
||||
schema,
|
||||
})
|
||||
.map_err(|error| Error::Schema {
|
||||
error,
|
||||
location: param.location,
|
||||
source_code: NamedSource::new(
|
||||
module.input_path.display().to_string(),
|
||||
module.code.clone(),
|
||||
),
|
||||
})
|
||||
Annotated::from_type(
|
||||
modules.into(),
|
||||
tipo_or_annotation(module, param),
|
||||
&mut definitions,
|
||||
)
|
||||
.map(|schema| Parameter {
|
||||
title: Some(param.arg_name.get_label()),
|
||||
schema,
|
||||
})
|
||||
.map_err(|error| Error::Schema {
|
||||
error,
|
||||
location: param.location,
|
||||
source_code: NamedSource::new(
|
||||
module.input_path.display().to_string(),
|
||||
module.code.clone(),
|
||||
),
|
||||
})
|
||||
})
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
@@ -118,48 +123,78 @@ impl Validator {
|
||||
parameters,
|
||||
datum: datum
|
||||
.map(|datum| {
|
||||
Annotated::from_type(modules.into(), &datum.tipo, &mut definitions).map_err(
|
||||
|error| Error::Schema {
|
||||
error,
|
||||
location: datum.location,
|
||||
source_code: NamedSource::new(
|
||||
module.input_path.display().to_string(),
|
||||
module.code.clone(),
|
||||
),
|
||||
},
|
||||
Annotated::from_type(
|
||||
modules.into(),
|
||||
tipo_or_annotation(module, datum),
|
||||
&mut definitions,
|
||||
)
|
||||
.map_err(|error| Error::Schema {
|
||||
error,
|
||||
location: datum.location,
|
||||
source_code: NamedSource::new(
|
||||
module.input_path.display().to_string(),
|
||||
module.code.clone(),
|
||||
),
|
||||
})
|
||||
})
|
||||
.transpose()?
|
||||
.map(|schema| Parameter {
|
||||
title: datum.map(|datum| datum.arg_name.get_label()),
|
||||
schema,
|
||||
}),
|
||||
redeemer: Annotated::from_type(modules.into(), &redeemer.tipo, &mut definitions)
|
||||
.map_err(|error| Error::Schema {
|
||||
error,
|
||||
location: redeemer.location,
|
||||
source_code: NamedSource::new(
|
||||
module.input_path.display().to_string(),
|
||||
module.code.clone(),
|
||||
redeemer: Annotated::from_type(
|
||||
modules.into(),
|
||||
tipo_or_annotation(module, redeemer),
|
||||
&mut definitions,
|
||||
)
|
||||
.map_err(|error| Error::Schema {
|
||||
error,
|
||||
location: redeemer.location,
|
||||
source_code: NamedSource::new(
|
||||
module.input_path.display().to_string(),
|
||||
module.code.clone(),
|
||||
),
|
||||
})
|
||||
.map(|schema| Parameter {
|
||||
title: Some(redeemer.arg_name.get_label()),
|
||||
schema: match datum {
|
||||
Some(..) if is_multi_validator => Annotated::as_wrapped_redeemer(
|
||||
&mut definitions,
|
||||
schema,
|
||||
redeemer.tipo.clone(),
|
||||
),
|
||||
})
|
||||
.map(|schema| Parameter {
|
||||
title: Some(redeemer.arg_name.get_label()),
|
||||
schema: match datum {
|
||||
Some(..) if is_multi_validator => Annotated::as_wrapped_redeemer(
|
||||
&mut definitions,
|
||||
schema,
|
||||
redeemer.tipo.clone(),
|
||||
),
|
||||
_ => schema,
|
||||
},
|
||||
})?,
|
||||
_ => schema,
|
||||
},
|
||||
})?,
|
||||
program: program.clone(),
|
||||
definitions,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn tipo_or_annotation<'a>(module: &'a CheckedModule, arg: &'a TypedArg) -> &'a Type {
|
||||
match *arg.tipo.borrow() {
|
||||
Type::App {
|
||||
module: ref module_name,
|
||||
name: ref type_name,
|
||||
..
|
||||
} if module_name.is_empty() && &type_name[..] == "Data" => match arg.annotation {
|
||||
Some(Annotation::Constructor { ref arguments, .. }) if !arguments.is_empty() => module
|
||||
.ast
|
||||
.type_info
|
||||
.annotations
|
||||
.get(
|
||||
arguments
|
||||
.first()
|
||||
.expect("guard ensures at least one element"),
|
||||
)
|
||||
.unwrap_or(&arg.tipo),
|
||||
_ => &arg.tipo,
|
||||
},
|
||||
_ => &arg.tipo,
|
||||
}
|
||||
}
|
||||
|
||||
impl Validator {
|
||||
pub fn apply(
|
||||
self,
|
||||
@@ -543,6 +578,23 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn annotated_data() {
|
||||
assert_validator!(
|
||||
r#"
|
||||
pub type Foo {
|
||||
foo: Int
|
||||
}
|
||||
|
||||
validator {
|
||||
fn annotated_data(datum: Data<Foo>, redeemer: Data, ctx: Void) {
|
||||
True
|
||||
}
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate_arguments_integer() {
|
||||
let definitions = fixture_definitions();
|
||||
|
||||
Reference in New Issue
Block a user