Authorize complete patterns as function args.
This is mainly a syntactic trick/sugar, but it's been pretty annoying to me for a while that we can't simply pattern-match/destructure single-variant constructors directly from the args list. A classic example is when writing property tests: ```ak test foo(params via both(bytearray(), int())) { let (bytes, ix) = params ... } ``` Now can be replaced simply with: ``` test foo((bytes, ix) via both(bytearray(), int())) { ... } ``` If feels natural, especially coming from the JavaScript, Haskell or Rust worlds and is mostly convenient. Behind the scene, the compiler does nothing more than re-writing the AST as the first form, with pre-generated arg names. Then, we fully rely on the existing type-checking capabilities and thus, works in a seamless way as if we were just pattern matching inline.
This commit is contained in:
parent
b6da42baf2
commit
858dfccc82
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
## v1.0.30-alpha - UNRELEASED
|
## v1.0.30-alpha - UNRELEASED
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **aiken-lang**: also authorize (complete) patterns in function arguments list instead of only variable names. @KtorZ
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- **aiken-lang**: duplicate import lines are now automatically merged instead of raising a warning. However, imports can no longer appear anywhere in the file and must come as the first definitions. @KtorZ
|
- **aiken-lang**: duplicate import lines are now automatically merged instead of raising a warning. However, imports can no longer appear anywhere in the file and must come as the first definitions. @KtorZ
|
||||||
|
|
|
@ -15,7 +15,7 @@ use std::{
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
};
|
};
|
||||||
use uplc::machine::runtime::Compressable;
|
use uplc::machine::runtime::Compressable;
|
||||||
use vec1::Vec1;
|
use vec1::{vec1, Vec1};
|
||||||
|
|
||||||
pub const BACKPASS_VARIABLE: &str = "_backpass";
|
pub const BACKPASS_VARIABLE: &str = "_backpass";
|
||||||
pub const CAPTURE_VARIABLE: &str = "_capture";
|
pub const CAPTURE_VARIABLE: &str = "_capture";
|
||||||
|
@ -797,6 +797,32 @@ pub enum ArgBy {
|
||||||
ByPattern(UntypedPattern),
|
ByPattern(UntypedPattern),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ArgBy {
|
||||||
|
pub fn into_extra_assignment(
|
||||||
|
self,
|
||||||
|
name: &ArgName,
|
||||||
|
annotation: Option<&Annotation>,
|
||||||
|
location: Span,
|
||||||
|
) -> Option<UntypedExpr> {
|
||||||
|
match self {
|
||||||
|
ArgBy::ByName(..) => None,
|
||||||
|
ArgBy::ByPattern(pattern) => Some(UntypedExpr::Assignment {
|
||||||
|
location,
|
||||||
|
value: Box::new(UntypedExpr::Var {
|
||||||
|
location,
|
||||||
|
name: name.get_name(),
|
||||||
|
}),
|
||||||
|
patterns: vec1![AssignmentPattern {
|
||||||
|
pattern,
|
||||||
|
location,
|
||||||
|
annotation: annotation.cloned(),
|
||||||
|
}],
|
||||||
|
kind: AssignmentKind::Let { backpassing: false },
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct UntypedArg {
|
pub struct UntypedArg {
|
||||||
pub by: ArgBy,
|
pub by: ArgBy,
|
||||||
|
|
|
@ -464,15 +464,17 @@ impl<'comments> Formatter<'comments> {
|
||||||
|
|
||||||
let doc_comments = self.doc_comments(arg.location.start);
|
let doc_comments = self.doc_comments(arg.location.start);
|
||||||
|
|
||||||
let doc = match arg.by {
|
let mut doc = match arg.by {
|
||||||
ArgBy::ByName(ref arg_name) => match &arg.annotation {
|
ArgBy::ByName(ref arg_name) => arg_name.to_doc(),
|
||||||
None => arg_name.to_doc(),
|
ArgBy::ByPattern(ref pattern) => self.pattern(pattern),
|
||||||
Some(a) => arg_name.to_doc().append(": ").append(self.annotation(a)),
|
|
||||||
}
|
|
||||||
.group(),
|
|
||||||
ArgBy::ByPattern(..) => todo!(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
doc = match &arg.annotation {
|
||||||
|
None => doc,
|
||||||
|
Some(a) => doc.append(": ").append(self.annotation(a)),
|
||||||
|
}
|
||||||
|
.group();
|
||||||
|
|
||||||
let doc = doc_comments.append(doc.group()).group();
|
let doc = doc_comments.append(doc.group()).group();
|
||||||
|
|
||||||
commented(doc, comments)
|
commented(doc, comments)
|
||||||
|
@ -483,12 +485,14 @@ impl<'comments> Formatter<'comments> {
|
||||||
|
|
||||||
let doc_comments = self.doc_comments(arg_via.arg.location.start);
|
let doc_comments = self.doc_comments(arg_via.arg.location.start);
|
||||||
|
|
||||||
let doc = match arg_via.arg.by {
|
let mut doc = match arg_via.arg.by {
|
||||||
ArgBy::ByName(ref arg_name) => match &arg_via.arg.annotation {
|
ArgBy::ByName(ref arg_name) => arg_name.to_doc(),
|
||||||
None => arg_name.to_doc(),
|
ArgBy::ByPattern(ref pattern) => self.pattern(pattern),
|
||||||
Some(a) => arg_name.to_doc().append(": ").append(self.annotation(a)),
|
};
|
||||||
},
|
|
||||||
ArgBy::ByPattern(..) => todo!(),
|
doc = match &arg_via.arg.annotation {
|
||||||
|
None => doc,
|
||||||
|
Some(a) => doc.append(": ").append(self.annotation(a)),
|
||||||
}
|
}
|
||||||
.append(" via ")
|
.append(" via ")
|
||||||
.append(self.expr(&arg_via.via, false))
|
.append(self.expr(&arg_via.via, false))
|
||||||
|
@ -1981,7 +1985,11 @@ impl<'a> Documentable<'a> for &'a ArgName {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pub_(public: bool) -> Document<'static> {
|
fn pub_(public: bool) -> Document<'static> {
|
||||||
if public { "pub ".to_doc() } else { nil() }
|
if public {
|
||||||
|
"pub ".to_doc()
|
||||||
|
} else {
|
||||||
|
nil()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Documentable<'a> for &'a UnqualifiedImport {
|
impl<'a> Documentable<'a> for &'a UnqualifiedImport {
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
ast,
|
ast,
|
||||||
ast::ArgBy::ByName,
|
|
||||||
expr::UntypedExpr,
|
expr::UntypedExpr,
|
||||||
parser::{annotation, error::ParseError, expr, token::Token, utils},
|
parser::{annotation, error::ParseError, expr, pattern, token::Token, utils},
|
||||||
};
|
};
|
||||||
use chumsky::prelude::*;
|
use chumsky::prelude::*;
|
||||||
|
|
||||||
|
@ -51,38 +50,45 @@ pub fn param(is_validator_param: bool) -> impl Parser<Token, ast::UntypedArg, Er
|
||||||
choice((
|
choice((
|
||||||
select! {Token::Name {name} => name}
|
select! {Token::Name {name} => name}
|
||||||
.then(select! {Token::DiscardName {name} => name})
|
.then(select! {Token::DiscardName {name} => name})
|
||||||
.map_with_span(|(label, name), span| ast::ArgName::Discarded {
|
.map_with_span(|(label, name), span| {
|
||||||
|
ast::ArgBy::ByName(ast::ArgName::Discarded {
|
||||||
label,
|
label,
|
||||||
name,
|
name,
|
||||||
location: span,
|
location: span,
|
||||||
|
})
|
||||||
}),
|
}),
|
||||||
select! {Token::DiscardName {name} => name}.map_with_span(|name, span| {
|
select! {Token::DiscardName {name} => name}.map_with_span(|name, span| {
|
||||||
ast::ArgName::Discarded {
|
ast::ArgBy::ByName(ast::ArgName::Discarded {
|
||||||
label: name.clone(),
|
label: name.clone(),
|
||||||
name,
|
name,
|
||||||
location: span,
|
location: span,
|
||||||
}
|
})
|
||||||
}),
|
}),
|
||||||
select! {Token::Name {name} => name}
|
select! {Token::Name {name} => name}
|
||||||
.then(select! {Token::Name {name} => name})
|
.then(select! {Token::Name {name} => name})
|
||||||
.map_with_span(|(label, name), span| ast::ArgName::Named {
|
.map_with_span(|(label, name), span| {
|
||||||
|
ast::ArgBy::ByName(ast::ArgName::Named {
|
||||||
label,
|
label,
|
||||||
name,
|
name,
|
||||||
location: span,
|
location: span,
|
||||||
|
})
|
||||||
}),
|
}),
|
||||||
select! {Token::Name {name} => name}.map_with_span(|name, span| ast::ArgName::Named {
|
select! {Token::Name {name} => name}.map_with_span(|name, span| {
|
||||||
|
ast::ArgBy::ByName(ast::ArgName::Named {
|
||||||
label: name.clone(),
|
label: name.clone(),
|
||||||
name,
|
name,
|
||||||
location: span,
|
location: span,
|
||||||
|
})
|
||||||
}),
|
}),
|
||||||
|
pattern().map(ast::ArgBy::ByPattern),
|
||||||
))
|
))
|
||||||
.then(just(Token::Colon).ignore_then(annotation()).or_not())
|
.then(just(Token::Colon).ignore_then(annotation()).or_not())
|
||||||
.map_with_span(move |(arg_name, annotation), span| ast::UntypedArg {
|
.map_with_span(move |(by, annotation), span| ast::UntypedArg {
|
||||||
location: span,
|
location: span,
|
||||||
annotation,
|
annotation,
|
||||||
doc: None,
|
doc: None,
|
||||||
is_validator_param,
|
is_validator_param,
|
||||||
by: ByName(arg_name),
|
by,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,4 +124,36 @@ mod tests {
|
||||||
"#
|
"#
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn function_by_pattern_no_annotation() {
|
||||||
|
assert_definition!(
|
||||||
|
r#"
|
||||||
|
fn foo(Foo { my_field }) {
|
||||||
|
my_field * 2
|
||||||
|
}
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn function_by_pattern_with_annotation() {
|
||||||
|
assert_definition!(
|
||||||
|
r#"
|
||||||
|
fn foo(Foo { my_field }: Foo) {
|
||||||
|
my_field * 2
|
||||||
|
}
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn function_by_pattern_with_alias() {
|
||||||
|
assert_definition!(
|
||||||
|
r#"
|
||||||
|
fn foo(Foo { my_field, .. } as x) {
|
||||||
|
my_field * x.my_other_field
|
||||||
|
}
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
---
|
||||||
|
source: crates/aiken-lang/src/parser/definition/function.rs
|
||||||
|
description: "Code:\n\nfn foo(Foo { my_field }) {\n my_field * 2\n}\n"
|
||||||
|
---
|
||||||
|
Fn(
|
||||||
|
Function {
|
||||||
|
arguments: [
|
||||||
|
UntypedArg {
|
||||||
|
by: ByPattern(
|
||||||
|
Constructor {
|
||||||
|
is_record: true,
|
||||||
|
location: 7..23,
|
||||||
|
name: "Foo",
|
||||||
|
arguments: [
|
||||||
|
CallArg {
|
||||||
|
label: Some(
|
||||||
|
"my_field",
|
||||||
|
),
|
||||||
|
location: 13..21,
|
||||||
|
value: Var {
|
||||||
|
location: 13..21,
|
||||||
|
name: "my_field",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
module: None,
|
||||||
|
constructor: (),
|
||||||
|
spread_location: None,
|
||||||
|
tipo: (),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
location: 7..23,
|
||||||
|
annotation: None,
|
||||||
|
doc: None,
|
||||||
|
is_validator_param: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
body: BinOp {
|
||||||
|
location: 31..43,
|
||||||
|
name: MultInt,
|
||||||
|
left: Var {
|
||||||
|
location: 31..39,
|
||||||
|
name: "my_field",
|
||||||
|
},
|
||||||
|
right: UInt {
|
||||||
|
location: 42..43,
|
||||||
|
value: "2",
|
||||||
|
base: Decimal {
|
||||||
|
numeric_underscore: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
doc: None,
|
||||||
|
location: 0..24,
|
||||||
|
name: "foo",
|
||||||
|
public: false,
|
||||||
|
return_annotation: None,
|
||||||
|
return_type: (),
|
||||||
|
end_position: 44,
|
||||||
|
on_test_failure: FailImmediately,
|
||||||
|
},
|
||||||
|
)
|
|
@ -0,0 +1,69 @@
|
||||||
|
---
|
||||||
|
source: crates/aiken-lang/src/parser/definition/function.rs
|
||||||
|
description: "Code:\n\nfn foo(Foo { my_field, .. } as x) {\n my_field * x.my_other_field\n}\n"
|
||||||
|
---
|
||||||
|
Fn(
|
||||||
|
Function {
|
||||||
|
arguments: [
|
||||||
|
UntypedArg {
|
||||||
|
by: ByPattern(
|
||||||
|
Assign {
|
||||||
|
name: "x",
|
||||||
|
location: 7..32,
|
||||||
|
pattern: Constructor {
|
||||||
|
is_record: true,
|
||||||
|
location: 7..27,
|
||||||
|
name: "Foo",
|
||||||
|
arguments: [
|
||||||
|
CallArg {
|
||||||
|
label: Some(
|
||||||
|
"my_field",
|
||||||
|
),
|
||||||
|
location: 13..21,
|
||||||
|
value: Var {
|
||||||
|
location: 13..21,
|
||||||
|
name: "my_field",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
module: None,
|
||||||
|
constructor: (),
|
||||||
|
spread_location: Some(
|
||||||
|
23..25,
|
||||||
|
),
|
||||||
|
tipo: (),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
location: 7..32,
|
||||||
|
annotation: None,
|
||||||
|
doc: None,
|
||||||
|
is_validator_param: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
body: BinOp {
|
||||||
|
location: 40..67,
|
||||||
|
name: MultInt,
|
||||||
|
left: Var {
|
||||||
|
location: 40..48,
|
||||||
|
name: "my_field",
|
||||||
|
},
|
||||||
|
right: FieldAccess {
|
||||||
|
location: 51..67,
|
||||||
|
label: "my_other_field",
|
||||||
|
container: Var {
|
||||||
|
location: 51..52,
|
||||||
|
name: "x",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
doc: None,
|
||||||
|
location: 0..33,
|
||||||
|
name: "foo",
|
||||||
|
public: false,
|
||||||
|
return_annotation: None,
|
||||||
|
return_type: (),
|
||||||
|
end_position: 68,
|
||||||
|
on_test_failure: FailImmediately,
|
||||||
|
},
|
||||||
|
)
|
|
@ -0,0 +1,69 @@
|
||||||
|
---
|
||||||
|
source: crates/aiken-lang/src/parser/definition/function.rs
|
||||||
|
description: "Code:\n\nfn foo(Foo { my_field }: Foo) {\n my_field * 2\n}\n"
|
||||||
|
---
|
||||||
|
Fn(
|
||||||
|
Function {
|
||||||
|
arguments: [
|
||||||
|
UntypedArg {
|
||||||
|
by: ByPattern(
|
||||||
|
Constructor {
|
||||||
|
is_record: true,
|
||||||
|
location: 7..23,
|
||||||
|
name: "Foo",
|
||||||
|
arguments: [
|
||||||
|
CallArg {
|
||||||
|
label: Some(
|
||||||
|
"my_field",
|
||||||
|
),
|
||||||
|
location: 13..21,
|
||||||
|
value: Var {
|
||||||
|
location: 13..21,
|
||||||
|
name: "my_field",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
module: None,
|
||||||
|
constructor: (),
|
||||||
|
spread_location: None,
|
||||||
|
tipo: (),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
location: 7..28,
|
||||||
|
annotation: Some(
|
||||||
|
Constructor {
|
||||||
|
location: 25..28,
|
||||||
|
module: None,
|
||||||
|
name: "Foo",
|
||||||
|
arguments: [],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
doc: None,
|
||||||
|
is_validator_param: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
body: BinOp {
|
||||||
|
location: 36..48,
|
||||||
|
name: MultInt,
|
||||||
|
left: Var {
|
||||||
|
location: 36..44,
|
||||||
|
name: "my_field",
|
||||||
|
},
|
||||||
|
right: UInt {
|
||||||
|
location: 47..48,
|
||||||
|
value: "2",
|
||||||
|
base: Decimal {
|
||||||
|
numeric_underscore: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
doc: None,
|
||||||
|
location: 0..29,
|
||||||
|
name: "foo",
|
||||||
|
public: false,
|
||||||
|
return_annotation: None,
|
||||||
|
return_type: (),
|
||||||
|
end_position: 49,
|
||||||
|
on_test_failure: FailImmediately,
|
||||||
|
},
|
||||||
|
)
|
|
@ -7,6 +7,7 @@ use crate::{
|
||||||
chain::{call::parser as call, field_access, tuple_index::parser as tuple_index, Chain},
|
chain::{call::parser as call, field_access, tuple_index::parser as tuple_index, Chain},
|
||||||
error::ParseError,
|
error::ParseError,
|
||||||
expr::{self, bytearray, int as uint, list, string, tuple, var},
|
expr::{self, bytearray, int as uint, list, string, tuple, var},
|
||||||
|
pattern,
|
||||||
token::Token,
|
token::Token,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -54,25 +55,28 @@ pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError
|
||||||
pub fn via() -> impl Parser<Token, ast::UntypedArgVia, Error = ParseError> {
|
pub fn via() -> impl Parser<Token, ast::UntypedArgVia, Error = ParseError> {
|
||||||
choice((
|
choice((
|
||||||
select! {Token::DiscardName {name} => name}.map_with_span(|name, span| {
|
select! {Token::DiscardName {name} => name}.map_with_span(|name, span| {
|
||||||
ast::ArgName::Discarded {
|
ast::ArgBy::ByName(ast::ArgName::Discarded {
|
||||||
label: name.clone(),
|
label: name.clone(),
|
||||||
name,
|
name,
|
||||||
location: span,
|
location: span,
|
||||||
}
|
})
|
||||||
}),
|
}),
|
||||||
select! {Token::Name {name} => name}.map_with_span(|name, location| ast::ArgName::Named {
|
select! {Token::Name {name} => name}.map_with_span(|name, location| {
|
||||||
|
ast::ArgBy::ByName(ast::ArgName::Named {
|
||||||
label: name.clone(),
|
label: name.clone(),
|
||||||
name,
|
name,
|
||||||
location,
|
location,
|
||||||
|
})
|
||||||
}),
|
}),
|
||||||
|
pattern().map(ast::ArgBy::ByPattern),
|
||||||
))
|
))
|
||||||
.then(just(Token::Colon).ignore_then(annotation()).or_not())
|
.then(just(Token::Colon).ignore_then(annotation()).or_not())
|
||||||
.map_with_span(|(arg_name, annotation), location| (arg_name, annotation, location))
|
.map_with_span(|(arg_name, annotation), location| (arg_name, annotation, location))
|
||||||
.then_ignore(just(Token::Via))
|
.then_ignore(just(Token::Via))
|
||||||
.then(fuzzer())
|
.then(fuzzer())
|
||||||
.map(|((arg_name, annotation, location), via)| ast::ArgVia {
|
.map(|((by, annotation, location), via)| ast::ArgVia {
|
||||||
arg: ast::UntypedArg {
|
arg: ast::UntypedArg {
|
||||||
by: ast::ArgBy::ByName(arg_name),
|
by,
|
||||||
annotation,
|
annotation,
|
||||||
location,
|
location,
|
||||||
doc: None,
|
doc: None,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
ast,
|
ast,
|
||||||
expr::{FnStyle, UntypedExpr},
|
expr::{FnStyle, UntypedExpr},
|
||||||
parser::{annotation, error::ParseError, token::Token},
|
parser::{annotation, error::ParseError, pattern, token::Token},
|
||||||
};
|
};
|
||||||
use chumsky::prelude::*;
|
use chumsky::prelude::*;
|
||||||
|
|
||||||
|
@ -32,25 +32,28 @@ pub fn params() -> impl Parser<Token, ast::UntypedArg, Error = ParseError> {
|
||||||
// TODO: return a better error when a label is provided `UnexpectedLabel`
|
// TODO: return a better error when a label is provided `UnexpectedLabel`
|
||||||
choice((
|
choice((
|
||||||
select! {Token::DiscardName {name} => name}.map_with_span(|name, span| {
|
select! {Token::DiscardName {name} => name}.map_with_span(|name, span| {
|
||||||
ast::ArgName::Discarded {
|
ast::ArgBy::ByName(ast::ArgName::Discarded {
|
||||||
label: name.clone(),
|
label: name.clone(),
|
||||||
name,
|
name,
|
||||||
location: span,
|
location: span,
|
||||||
}
|
})
|
||||||
}),
|
}),
|
||||||
select! {Token::Name {name} => name}.map_with_span(|name, span| ast::ArgName::Named {
|
select! {Token::Name {name} => name}.map_with_span(|name, span| {
|
||||||
|
ast::ArgBy::ByName(ast::ArgName::Named {
|
||||||
label: name.clone(),
|
label: name.clone(),
|
||||||
name,
|
name,
|
||||||
location: span,
|
location: span,
|
||||||
|
})
|
||||||
}),
|
}),
|
||||||
|
pattern().map(ast::ArgBy::ByPattern),
|
||||||
))
|
))
|
||||||
.then(just(Token::Colon).ignore_then(annotation()).or_not())
|
.then(just(Token::Colon).ignore_then(annotation()).or_not())
|
||||||
.map_with_span(|(arg_name, annotation), span| ast::UntypedArg {
|
.map_with_span(|(by, annotation), span| ast::UntypedArg {
|
||||||
is_validator_param: false,
|
is_validator_param: false,
|
||||||
location: span,
|
location: span,
|
||||||
annotation,
|
annotation,
|
||||||
doc: None,
|
doc: None,
|
||||||
by: ast::ArgBy::ByName(arg_name),
|
by,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,4 +65,19 @@ mod tests {
|
||||||
fn anonymous_function_basic() {
|
fn anonymous_function_basic() {
|
||||||
assert_expr!(r#"fn (a: Int) -> Int { a + 1 }"#);
|
assert_expr!(r#"fn (a: Int) -> Int { a + 1 }"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn anonymous_function_by_pattern_no_annotation() {
|
||||||
|
assert_expr!(r#"fn (Foo { my_field }) { my_field * 2 }"#);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn anonymous_function_by_pattern_with_annotation() {
|
||||||
|
assert_expr!(r#"fn (Foo { my_field } : Foo) { my_field * 2 }"#);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn anonymous_function_by_pattern_with_alias() {
|
||||||
|
assert_expr!(r#"fn (Foo { my_field, .. } as x) { my_field * my_other_field }"#);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
---
|
||||||
|
source: crates/aiken-lang/src/parser/expr/anonymous_function.rs
|
||||||
|
description: "Code:\n\nfn (Foo { my_field }) { my_field * 2 }"
|
||||||
|
---
|
||||||
|
Fn {
|
||||||
|
location: 0..38,
|
||||||
|
fn_style: Plain,
|
||||||
|
arguments: [
|
||||||
|
UntypedArg {
|
||||||
|
by: ByPattern(
|
||||||
|
Constructor {
|
||||||
|
is_record: true,
|
||||||
|
location: 4..20,
|
||||||
|
name: "Foo",
|
||||||
|
arguments: [
|
||||||
|
CallArg {
|
||||||
|
label: Some(
|
||||||
|
"my_field",
|
||||||
|
),
|
||||||
|
location: 10..18,
|
||||||
|
value: Var {
|
||||||
|
location: 10..18,
|
||||||
|
name: "my_field",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
module: None,
|
||||||
|
constructor: (),
|
||||||
|
spread_location: None,
|
||||||
|
tipo: (),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
location: 4..20,
|
||||||
|
annotation: None,
|
||||||
|
doc: None,
|
||||||
|
is_validator_param: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
body: BinOp {
|
||||||
|
location: 24..36,
|
||||||
|
name: MultInt,
|
||||||
|
left: Var {
|
||||||
|
location: 24..32,
|
||||||
|
name: "my_field",
|
||||||
|
},
|
||||||
|
right: UInt {
|
||||||
|
location: 35..36,
|
||||||
|
value: "2",
|
||||||
|
base: Decimal {
|
||||||
|
numeric_underscore: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
return_annotation: None,
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
---
|
||||||
|
source: crates/aiken-lang/src/parser/expr/anonymous_function.rs
|
||||||
|
description: "Code:\n\nfn (Foo { my_field, .. } as x) { my_field * my_other_field }"
|
||||||
|
---
|
||||||
|
Fn {
|
||||||
|
location: 0..60,
|
||||||
|
fn_style: Plain,
|
||||||
|
arguments: [
|
||||||
|
UntypedArg {
|
||||||
|
by: ByPattern(
|
||||||
|
Assign {
|
||||||
|
name: "x",
|
||||||
|
location: 4..29,
|
||||||
|
pattern: Constructor {
|
||||||
|
is_record: true,
|
||||||
|
location: 4..24,
|
||||||
|
name: "Foo",
|
||||||
|
arguments: [
|
||||||
|
CallArg {
|
||||||
|
label: Some(
|
||||||
|
"my_field",
|
||||||
|
),
|
||||||
|
location: 10..18,
|
||||||
|
value: Var {
|
||||||
|
location: 10..18,
|
||||||
|
name: "my_field",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
module: None,
|
||||||
|
constructor: (),
|
||||||
|
spread_location: Some(
|
||||||
|
20..22,
|
||||||
|
),
|
||||||
|
tipo: (),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
location: 4..29,
|
||||||
|
annotation: None,
|
||||||
|
doc: None,
|
||||||
|
is_validator_param: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
body: BinOp {
|
||||||
|
location: 33..58,
|
||||||
|
name: MultInt,
|
||||||
|
left: Var {
|
||||||
|
location: 33..41,
|
||||||
|
name: "my_field",
|
||||||
|
},
|
||||||
|
right: Var {
|
||||||
|
location: 44..58,
|
||||||
|
name: "my_other_field",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
return_annotation: None,
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
---
|
||||||
|
source: crates/aiken-lang/src/parser/expr/anonymous_function.rs
|
||||||
|
description: "Code:\n\nfn (Foo { my_field } : Foo) { my_field * 2 }"
|
||||||
|
---
|
||||||
|
Fn {
|
||||||
|
location: 0..44,
|
||||||
|
fn_style: Plain,
|
||||||
|
arguments: [
|
||||||
|
UntypedArg {
|
||||||
|
by: ByPattern(
|
||||||
|
Constructor {
|
||||||
|
is_record: true,
|
||||||
|
location: 4..20,
|
||||||
|
name: "Foo",
|
||||||
|
arguments: [
|
||||||
|
CallArg {
|
||||||
|
label: Some(
|
||||||
|
"my_field",
|
||||||
|
),
|
||||||
|
location: 10..18,
|
||||||
|
value: Var {
|
||||||
|
location: 10..18,
|
||||||
|
name: "my_field",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
module: None,
|
||||||
|
constructor: (),
|
||||||
|
spread_location: None,
|
||||||
|
tipo: (),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
location: 4..26,
|
||||||
|
annotation: Some(
|
||||||
|
Constructor {
|
||||||
|
location: 23..26,
|
||||||
|
module: None,
|
||||||
|
name: "Foo",
|
||||||
|
arguments: [],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
doc: None,
|
||||||
|
is_validator_param: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
body: BinOp {
|
||||||
|
location: 30..42,
|
||||||
|
name: MultInt,
|
||||||
|
left: Var {
|
||||||
|
location: 30..38,
|
||||||
|
name: "my_field",
|
||||||
|
},
|
||||||
|
right: UInt {
|
||||||
|
location: 41..42,
|
||||||
|
value: "2",
|
||||||
|
base: Decimal {
|
||||||
|
numeric_underscore: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
return_annotation: None,
|
||||||
|
}
|
|
@ -2539,3 +2539,37 @@ fn mutually_recursive_1() {
|
||||||
|
|
||||||
assert!(check(parse(source_code)).is_ok());
|
assert!(check(parse(source_code)).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fn_single_variant_pattern() {
|
||||||
|
let source_code = r#"
|
||||||
|
pub type Foo {
|
||||||
|
a: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn foo(Foo { a }) {
|
||||||
|
a + 1
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
assert!(dbg!(check(parse(source_code))).is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fn_multi_variant_pattern() {
|
||||||
|
let source_code = r#"
|
||||||
|
type Foo {
|
||||||
|
A { a: Int }
|
||||||
|
B { b: Int }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn foo(A { a }) {
|
||||||
|
a + 1
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
assert!(matches!(
|
||||||
|
dbg!(check_validator(parse(source_code))),
|
||||||
|
Err((_, Error::NotExhaustivePatternMatch { .. }))
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
|
@ -883,3 +883,68 @@ fn format_pairs() {
|
||||||
}"#
|
}"#
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn format_fn_pattern() {
|
||||||
|
assert_format!(
|
||||||
|
r#"
|
||||||
|
pub fn foo(Foo { a, b, .. }) {
|
||||||
|
todo
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bar([Bar] : List<Bar>) {
|
||||||
|
todo
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn baz((Baz, Baz) as x) {
|
||||||
|
todo
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fiz(Pair(fst, snd) as x: Pair<Int, Int>) {
|
||||||
|
todo
|
||||||
|
}
|
||||||
|
|
||||||
|
test buz((a, b) via some_fuzzer()) {
|
||||||
|
todo
|
||||||
|
}
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn format_anon_fn_pattern() {
|
||||||
|
assert_format!(
|
||||||
|
r#"
|
||||||
|
pub fn main() {
|
||||||
|
let foo = fn (Foo { a, b, .. }) { todo }
|
||||||
|
let bar = fn ([Bar] : List<Bar>) { todo }
|
||||||
|
let baz = fn ((Baz, Baz) as x) { todo }
|
||||||
|
let fiz = fn (Pair(fst, snd) as x: Pair<Int, Int>) { todo }
|
||||||
|
todo
|
||||||
|
}
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn format_validator_pattern() {
|
||||||
|
assert_format!(
|
||||||
|
r#"
|
||||||
|
validator(Foo { a, b, .. }) {
|
||||||
|
fn foo() { todo }
|
||||||
|
}
|
||||||
|
|
||||||
|
validator([Bar] : List<Bar>) {
|
||||||
|
fn bar() { todo }
|
||||||
|
}
|
||||||
|
|
||||||
|
validator((Baz, Baz) as x) {
|
||||||
|
fn baz() { todo }
|
||||||
|
}
|
||||||
|
|
||||||
|
validator((fst, snd) as x: Pair<Int, Int>) {
|
||||||
|
fn fiz() { todo }
|
||||||
|
}
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
---
|
||||||
|
source: crates/aiken-lang/src/tests/format.rs
|
||||||
|
description: "Code:\n\npub fn main() {\n let foo = fn (Foo { a, b, .. }) { todo }\n let bar = fn ([Bar] : List<Bar>) { todo }\n let baz = fn ((Baz, Baz) as x) { todo }\n let fiz = fn (Pair(fst, snd) as x: Pair<Int, Int>) { todo }\n todo\n}\n"
|
||||||
|
---
|
||||||
|
pub fn main() {
|
||||||
|
let foo =
|
||||||
|
fn(Foo { a, b, .. }) {
|
||||||
|
todo
|
||||||
|
}
|
||||||
|
let bar =
|
||||||
|
fn([Bar]: List<Bar>) {
|
||||||
|
todo
|
||||||
|
}
|
||||||
|
let baz =
|
||||||
|
fn((Baz, Baz) as x) {
|
||||||
|
todo
|
||||||
|
}
|
||||||
|
let fiz =
|
||||||
|
fn(Pair(fst, snd) as x: Pair<Int, Int>) {
|
||||||
|
todo
|
||||||
|
}
|
||||||
|
todo
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
---
|
||||||
|
source: crates/aiken-lang/src/tests/format.rs
|
||||||
|
description: "Code:\n\npub fn foo(Foo { a, b, .. }) {\n todo\n}\n\npub fn bar([Bar] : List<Bar>) {\n todo\n}\n\npub fn baz((Baz, Baz) as x) {\n todo\n}\n\npub fn fiz(Pair(fst, snd) as x: Pair<Int, Int>) {\n todo\n}\n\ntest buz((a, b) via some_fuzzer()) {\n todo\n}\n"
|
||||||
|
---
|
||||||
|
pub fn foo(Foo { a, b, .. }) {
|
||||||
|
todo
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bar([Bar]: List<Bar>) {
|
||||||
|
todo
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn baz((Baz, Baz) as x) {
|
||||||
|
todo
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fiz(Pair(fst, snd) as x: Pair<Int, Int>) {
|
||||||
|
todo
|
||||||
|
}
|
||||||
|
|
||||||
|
test buz((a, b) via some_fuzzer()) {
|
||||||
|
todo
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
---
|
||||||
|
source: crates/aiken-lang/src/tests/format.rs
|
||||||
|
description: "Code:\n\nvalidator(Foo { a, b, .. }) {\n fn foo() { todo }\n}\n\nvalidator([Bar] : List<Bar>) {\n fn bar() { todo }\n}\n\nvalidator((Baz, Baz) as x) {\n fn baz() { todo }\n}\n\nvalidator((fst, snd) as x: Pair<Int, Int>) {\n fn fiz() { todo }\n}\n"
|
||||||
|
---
|
||||||
|
validator(Foo { a, b, .. }) {
|
||||||
|
fn foo() {
|
||||||
|
todo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validator([Bar]: List<Bar>) {
|
||||||
|
fn bar() {
|
||||||
|
todo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validator((Baz, Baz) as x) {
|
||||||
|
fn baz() {
|
||||||
|
todo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validator((fst, snd) as x: Pair<Int, Int>) {
|
||||||
|
fn fiz() {
|
||||||
|
todo
|
||||||
|
}
|
||||||
|
}
|
|
@ -59,6 +59,39 @@ pub(crate) fn infer_function(
|
||||||
return_type: _,
|
return_type: _,
|
||||||
} = fun;
|
} = fun;
|
||||||
|
|
||||||
|
let mut extra_let_assignments = Vec::new();
|
||||||
|
for (i, arg) in arguments.iter().enumerate() {
|
||||||
|
let let_assignment = arg.by.clone().into_extra_assignment(
|
||||||
|
&arg.arg_name(i),
|
||||||
|
arg.annotation.as_ref(),
|
||||||
|
arg.location,
|
||||||
|
);
|
||||||
|
match let_assignment {
|
||||||
|
None => {}
|
||||||
|
Some(expr) => extra_let_assignments.push(expr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let sequence;
|
||||||
|
|
||||||
|
let body = if extra_let_assignments.is_empty() {
|
||||||
|
body
|
||||||
|
} else if let UntypedExpr::Sequence { expressions, .. } = body {
|
||||||
|
extra_let_assignments.extend(expressions.clone());
|
||||||
|
sequence = UntypedExpr::Sequence {
|
||||||
|
expressions: extra_let_assignments,
|
||||||
|
location: *location,
|
||||||
|
};
|
||||||
|
&sequence
|
||||||
|
} else {
|
||||||
|
extra_let_assignments.extend([body.clone()]);
|
||||||
|
sequence = UntypedExpr::Sequence {
|
||||||
|
expressions: extra_let_assignments,
|
||||||
|
location: body.location(),
|
||||||
|
};
|
||||||
|
&sequence
|
||||||
|
};
|
||||||
|
|
||||||
let preregistered_fn = environment
|
let preregistered_fn = environment
|
||||||
.get_variable(name)
|
.get_variable(name)
|
||||||
.expect("Could not find preregistered type for function");
|
.expect("Could not find preregistered type for function");
|
||||||
|
@ -331,9 +364,13 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
|
|
||||||
let mut arguments = Vec::new();
|
let mut arguments = Vec::new();
|
||||||
|
|
||||||
|
let mut extra_let_assignments = Vec::new();
|
||||||
for (i, arg) in args.into_iter().enumerate() {
|
for (i, arg) in args.into_iter().enumerate() {
|
||||||
let arg = self.infer_param(arg, expected_args.get(i).cloned(), i)?;
|
let (arg, extra_let_assignment) =
|
||||||
|
self.infer_param(arg, expected_args.get(i).cloned(), i)?;
|
||||||
|
if let Some(expr) = extra_let_assignment {
|
||||||
|
extra_let_assignments.push(expr);
|
||||||
|
}
|
||||||
arguments.push(arg);
|
arguments.push(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,6 +379,28 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let body_location = body.location();
|
||||||
|
|
||||||
|
let body = if extra_let_assignments.is_empty() {
|
||||||
|
body
|
||||||
|
} else if let UntypedExpr::Sequence {
|
||||||
|
location,
|
||||||
|
expressions,
|
||||||
|
} = body
|
||||||
|
{
|
||||||
|
extra_let_assignments.extend(expressions);
|
||||||
|
UntypedExpr::Sequence {
|
||||||
|
expressions: extra_let_assignments,
|
||||||
|
location,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
extra_let_assignments.extend([body]);
|
||||||
|
UntypedExpr::Sequence {
|
||||||
|
expressions: extra_let_assignments,
|
||||||
|
location: body_location,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
self.infer_fn_with_known_types(arguments, body, return_type)
|
self.infer_fn_with_known_types(arguments, body, return_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1071,13 +1130,12 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Handle arg pattern
|
|
||||||
fn infer_param(
|
fn infer_param(
|
||||||
&mut self,
|
&mut self,
|
||||||
untyped_arg: UntypedArg,
|
untyped_arg: UntypedArg,
|
||||||
expected: Option<Rc<Type>>,
|
expected: Option<Rc<Type>>,
|
||||||
ix: usize,
|
ix: usize,
|
||||||
) -> Result<TypedArg, Error> {
|
) -> Result<(TypedArg, Option<UntypedExpr>), Error> {
|
||||||
let arg_name = untyped_arg.arg_name(ix);
|
let arg_name = untyped_arg.arg_name(ix);
|
||||||
|
|
||||||
let UntypedArg {
|
let UntypedArg {
|
||||||
|
@ -1102,14 +1160,18 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
self.unify(expected, tipo.clone(), location, false)?;
|
self.unify(expected, tipo.clone(), location, false)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(TypedArg {
|
let extra_assignment = by.into_extra_assignment(&arg_name, annotation.as_ref(), location);
|
||||||
|
|
||||||
|
let typed_arg = TypedArg {
|
||||||
arg_name,
|
arg_name,
|
||||||
location,
|
location,
|
||||||
annotation,
|
annotation,
|
||||||
tipo,
|
tipo,
|
||||||
is_validator_param,
|
is_validator_param,
|
||||||
doc,
|
doc,
|
||||||
})
|
};
|
||||||
|
|
||||||
|
Ok((typed_arg, extra_assignment))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infer_assignment(
|
fn infer_assignment(
|
||||||
|
|
|
@ -507,10 +507,8 @@ impl Prng {
|
||||||
fn as_prng(cst: &PlutusData) -> Prng {
|
fn as_prng(cst: &PlutusData) -> Prng {
|
||||||
if let PlutusData::Constr(Constr { tag, fields, .. }) = cst {
|
if let PlutusData::Constr(Constr { tag, fields, .. }) = cst {
|
||||||
if *tag == 121 + Prng::SEEDED {
|
if *tag == 121 + Prng::SEEDED {
|
||||||
if let [
|
if let [PlutusData::BoundedBytes(bytes), PlutusData::BoundedBytes(choices)] =
|
||||||
PlutusData::BoundedBytes(bytes),
|
&fields[..]
|
||||||
PlutusData::BoundedBytes(choices),
|
|
||||||
] = &fields[..]
|
|
||||||
{
|
{
|
||||||
return Prng::Seeded {
|
return Prng::Seeded {
|
||||||
choices: choices.to_vec(),
|
choices: choices.to_vec(),
|
||||||
|
@ -1089,11 +1087,9 @@ impl TryFrom<TypedExpr> for Assertion<TypedExpr> {
|
||||||
final_else,
|
final_else,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
if let [
|
if let [IfBranch {
|
||||||
IfBranch {
|
|
||||||
condition, body, ..
|
condition, body, ..
|
||||||
},
|
}] = &branches[..]
|
||||||
] = &branches[..]
|
|
||||||
{
|
{
|
||||||
let then_is_true = match body {
|
let then_is_true = match body {
|
||||||
TypedExpr::Var {
|
TypedExpr::Var {
|
||||||
|
@ -1512,14 +1508,13 @@ mod test {
|
||||||
}
|
}
|
||||||
"#});
|
"#});
|
||||||
|
|
||||||
assert!(
|
assert!(prop
|
||||||
prop.run::<()>(
|
.run::<()>(
|
||||||
42,
|
42,
|
||||||
PropertyTest::DEFAULT_MAX_SUCCESS,
|
PropertyTest::DEFAULT_MAX_SUCCESS,
|
||||||
&PlutusVersion::default()
|
&PlutusVersion::default()
|
||||||
)
|
)
|
||||||
.is_success()
|
.is_success());
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
# This file was generated by Aiken
|
||||||
|
# You typically do not need to edit this file
|
||||||
|
|
||||||
|
[[requirements]]
|
||||||
|
name = "aiken-lang/stdlib"
|
||||||
|
version = "main"
|
||||||
|
source = "github"
|
||||||
|
|
||||||
|
[[requirements]]
|
||||||
|
name = "aiken-lang/fuzz"
|
||||||
|
version = "main"
|
||||||
|
source = "github"
|
||||||
|
|
||||||
|
[[packages]]
|
||||||
|
name = "aiken-lang/stdlib"
|
||||||
|
version = "main"
|
||||||
|
requirements = []
|
||||||
|
source = "github"
|
||||||
|
|
||||||
|
[[packages]]
|
||||||
|
name = "aiken-lang/fuzz"
|
||||||
|
version = "main"
|
||||||
|
requirements = []
|
||||||
|
source = "github"
|
||||||
|
|
||||||
|
[etags]
|
||||||
|
"aiken-lang/fuzz@main" = [{ secs_since_epoch = 1717767691, nanos_since_epoch = 206091000 }, "98cf81aa68f9ccf68bc5aba9be06d06cb1db6e8eff60b668ed5e8ddf3588206b"]
|
||||||
|
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1717767690, nanos_since_epoch = 920449000 }, "a746f5b5cd3c2ca5dc19c43bcfc64230c546fafea2ba5f8e340c227b85886078"]
|
|
@ -0,0 +1,21 @@
|
||||||
|
name = "aiken-lang/104"
|
||||||
|
version = "0.0.0"
|
||||||
|
compiler = "v1.0.29-alpha"
|
||||||
|
plutus = "v2"
|
||||||
|
license = "Apache-2.0"
|
||||||
|
description = "Aiken contracts for project 'aiken-lang/104'"
|
||||||
|
|
||||||
|
[repository]
|
||||||
|
user = "aiken-lang"
|
||||||
|
project = "104"
|
||||||
|
platform = "github"
|
||||||
|
|
||||||
|
[[dependencies]]
|
||||||
|
name = "aiken-lang/stdlib"
|
||||||
|
version = "main"
|
||||||
|
source = "github"
|
||||||
|
|
||||||
|
[[dependencies]]
|
||||||
|
name = "aiken-lang/fuzz"
|
||||||
|
version = "main"
|
||||||
|
source = "github"
|
|
@ -0,0 +1,80 @@
|
||||||
|
{
|
||||||
|
"preamble": {
|
||||||
|
"title": "aiken-lang/104",
|
||||||
|
"description": "Aiken contracts for project 'aiken-lang/104'",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"plutusVersion": "v2",
|
||||||
|
"compiler": {
|
||||||
|
"name": "Aiken",
|
||||||
|
"version": "v1.0.29-alpha+257bd23"
|
||||||
|
},
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
|
"validators": [
|
||||||
|
{
|
||||||
|
"title": "tests.foo_3",
|
||||||
|
"redeemer": {
|
||||||
|
"title": "_data",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Data"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"title": "th_arg",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/tests~1Foo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"compiledCode": "582401000032323222253330043370e6eb4c018c014dd5001a400429309b2b2b9a5573cae841",
|
||||||
|
"hash": "047dafbc61fb4a550a28398bde3680c48ff2000cf1022efc883124cd"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"definitions": {
|
||||||
|
"Bool": {
|
||||||
|
"title": "Bool",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"title": "False",
|
||||||
|
"dataType": "constructor",
|
||||||
|
"index": 0,
|
||||||
|
"fields": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "True",
|
||||||
|
"dataType": "constructor",
|
||||||
|
"index": 1,
|
||||||
|
"fields": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Data": {
|
||||||
|
"title": "Data",
|
||||||
|
"description": "Any Plutus data."
|
||||||
|
},
|
||||||
|
"Int": {
|
||||||
|
"dataType": "integer"
|
||||||
|
},
|
||||||
|
"tests/Foo": {
|
||||||
|
"title": "Foo",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"title": "Foo",
|
||||||
|
"dataType": "constructor",
|
||||||
|
"index": 0,
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"title": "a0",
|
||||||
|
"$ref": "#/definitions/Int"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "a1",
|
||||||
|
"$ref": "#/definitions/Bool"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
use aiken/fuzz
|
||||||
|
|
||||||
|
type Foo {
|
||||||
|
a0: Int,
|
||||||
|
a1: Bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo_1(Foo { a0, .. }) -> Int {
|
||||||
|
a0 + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo_2(Foo { a0, a1 } as foo) -> Int {
|
||||||
|
if a1 {
|
||||||
|
a0 + 1
|
||||||
|
} else {
|
||||||
|
foo.a0 - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validator(Foo { a0, .. }: Foo) {
|
||||||
|
fn foo_3(_data, _redeemer) {
|
||||||
|
a0 == 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test example_1() {
|
||||||
|
foo_1(Foo { a0: 1, a1: False }) == 2
|
||||||
|
}
|
||||||
|
|
||||||
|
test example_2() {
|
||||||
|
foo_2(Foo { a0: 1, a1: False }) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
test example_3() {
|
||||||
|
foo_3(Foo { a0: 1, a1: False }, "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
test example_4() {
|
||||||
|
let foo_4 = fn(Foo { a1, .. }) { a1 }
|
||||||
|
foo_4(Foo { a0: 1, a1: True })
|
||||||
|
}
|
||||||
|
|
||||||
|
test example_5((a, b) via fuzz.both(fuzz.int(), fuzz.int())) {
|
||||||
|
a + b == b + a
|
||||||
|
}
|
Loading…
Reference in New Issue