Allow test definition to carry one parameter
The parameter is special as it takes no annotation but a 'via' keyword followed by an expression that should unify to a Fuzzer<a>, where Fuzzer<a> = fn(Seed) -> (Seed, a). The current commit only allow name identifiers for now. Ultimately, this may allow full expressions.
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
---
|
||||
source: crates/aiken-lang/src/parser/definition/test.rs
|
||||
description: "Code:\n\ntest foo(x via f, y via g) {\n True\n}\n"
|
||||
---
|
||||
Test(
|
||||
Function {
|
||||
arguments: [
|
||||
ArgVia {
|
||||
arg_name: Named {
|
||||
name: "x",
|
||||
label: "x",
|
||||
location: 9..10,
|
||||
is_validator_param: false,
|
||||
},
|
||||
location: 9..16,
|
||||
via: DefinitionIdentifier {
|
||||
module: None,
|
||||
name: "f",
|
||||
},
|
||||
tipo: (),
|
||||
},
|
||||
ArgVia {
|
||||
arg_name: Named {
|
||||
name: "y",
|
||||
label: "y",
|
||||
location: 18..19,
|
||||
is_validator_param: false,
|
||||
},
|
||||
location: 18..25,
|
||||
via: DefinitionIdentifier {
|
||||
module: None,
|
||||
name: "g",
|
||||
},
|
||||
tipo: (),
|
||||
},
|
||||
],
|
||||
body: Var {
|
||||
location: 33..37,
|
||||
name: "True",
|
||||
},
|
||||
doc: None,
|
||||
location: 0..26,
|
||||
name: "foo",
|
||||
public: false,
|
||||
return_annotation: None,
|
||||
return_type: (),
|
||||
end_position: 38,
|
||||
can_error: false,
|
||||
},
|
||||
)
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
source: crates/aiken-lang/src/parser/definition/test.rs
|
||||
description: "Code:\n\ntest foo(x via fuzz.any_int) {\n True\n}\n"
|
||||
---
|
||||
Test(
|
||||
Function {
|
||||
arguments: [
|
||||
ArgVia {
|
||||
arg_name: Named {
|
||||
name: "x",
|
||||
label: "x",
|
||||
location: 9..10,
|
||||
is_validator_param: false,
|
||||
},
|
||||
location: 9..27,
|
||||
via: DefinitionIdentifier {
|
||||
module: Some(
|
||||
"fuzz",
|
||||
),
|
||||
name: "any_int",
|
||||
},
|
||||
tipo: (),
|
||||
},
|
||||
],
|
||||
body: Var {
|
||||
location: 35..39,
|
||||
name: "True",
|
||||
},
|
||||
doc: None,
|
||||
location: 0..28,
|
||||
name: "foo",
|
||||
public: false,
|
||||
return_annotation: None,
|
||||
return_type: (),
|
||||
end_position: 40,
|
||||
can_error: false,
|
||||
},
|
||||
)
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
source: crates/aiken-lang/src/parser/definition/test.rs
|
||||
description: "Code:\n\ntest foo() {\n True\n}\n"
|
||||
---
|
||||
Test(
|
||||
Function {
|
||||
arguments: [],
|
||||
body: Var {
|
||||
location: 17..21,
|
||||
name: "True",
|
||||
},
|
||||
doc: None,
|
||||
location: 0..10,
|
||||
name: "foo",
|
||||
public: false,
|
||||
return_annotation: None,
|
||||
return_type: (),
|
||||
end_position: 22,
|
||||
can_error: false,
|
||||
},
|
||||
)
|
||||
@@ -13,8 +13,12 @@ pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError
|
||||
.or_not()
|
||||
.then_ignore(just(Token::Test))
|
||||
.then(select! {Token::Name {name} => name})
|
||||
.then_ignore(just(Token::LeftParen))
|
||||
.then_ignore(just(Token::RightParen))
|
||||
.then(
|
||||
via()
|
||||
.separated_by(just(Token::Comma))
|
||||
.allow_trailing()
|
||||
.delimited_by(just(Token::LeftParen), just(Token::RightParen)),
|
||||
)
|
||||
.then(just(Token::Fail).ignored().or_not())
|
||||
.map_with_span(|name, span| (name, span))
|
||||
.then(
|
||||
@@ -22,26 +26,72 @@ pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError
|
||||
.or_not()
|
||||
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)),
|
||||
)
|
||||
.map_with_span(|((((old_fail, name), fail), span_end), body), span| {
|
||||
ast::UntypedDefinition::Test(ast::Function {
|
||||
arguments: vec![],
|
||||
body: body.unwrap_or_else(|| UntypedExpr::todo(None, span)),
|
||||
doc: None,
|
||||
location: span_end,
|
||||
end_position: span.end - 1,
|
||||
.map_with_span(
|
||||
|(((((old_fail, name), arguments), fail), span_end), body), span| {
|
||||
ast::UntypedDefinition::Test(ast::Function {
|
||||
arguments,
|
||||
body: body.unwrap_or_else(|| UntypedExpr::todo(None, span)),
|
||||
doc: None,
|
||||
location: span_end,
|
||||
end_position: span.end - 1,
|
||||
name,
|
||||
public: false,
|
||||
return_annotation: Some(ast::Annotation::boolean(span)),
|
||||
return_type: (),
|
||||
can_error: fail.is_some() || old_fail.is_some(),
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn via() -> impl Parser<Token, ast::UntypedArgVia, Error = ParseError> {
|
||||
choice((
|
||||
select! {Token::DiscardName {name} => name}.map_with_span(|name, span| {
|
||||
ast::ArgName::Discarded {
|
||||
label: name.clone(),
|
||||
name,
|
||||
public: false,
|
||||
return_annotation: None,
|
||||
return_type: (),
|
||||
can_error: fail.is_some() || old_fail.is_some(),
|
||||
})
|
||||
})
|
||||
location: span,
|
||||
}
|
||||
}),
|
||||
select! {Token::Name {name} => name}.map_with_span(move |name, location| {
|
||||
ast::ArgName::Named {
|
||||
label: name.clone(),
|
||||
name,
|
||||
location,
|
||||
is_validator_param: false,
|
||||
}
|
||||
}),
|
||||
))
|
||||
.then_ignore(just(Token::Via))
|
||||
.then(
|
||||
select! { Token::Name { name } => name }
|
||||
.then_ignore(just(Token::Dot))
|
||||
.or_not(),
|
||||
)
|
||||
.then(select! { Token::Name { name } => name })
|
||||
.map_with_span(|((arg_name, module), name), location| ast::ArgVia {
|
||||
arg_name,
|
||||
via: ast::DefinitionIdentifier { module, name },
|
||||
tipo: (),
|
||||
location,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::assert_definition;
|
||||
|
||||
#[test]
|
||||
fn def_test() {
|
||||
assert_definition!(
|
||||
r#"
|
||||
test foo() {
|
||||
True
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn def_test_fail() {
|
||||
assert_definition!(
|
||||
@@ -54,4 +104,26 @@ mod tests {
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn def_property_test() {
|
||||
assert_definition!(
|
||||
r#"
|
||||
test foo(x via fuzz.any_int) {
|
||||
True
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn def_invalid_property_test() {
|
||||
assert_definition!(
|
||||
r#"
|
||||
test foo(x via f, y via g) {
|
||||
True
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,6 +240,7 @@ pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = ParseError> {
|
||||
"type" => Token::Type,
|
||||
"when" => Token::When,
|
||||
"validator" => Token::Validator,
|
||||
"via" => Token::Via,
|
||||
_ => {
|
||||
if s.chars().next().map_or(false, |c| c.is_uppercase()) {
|
||||
Token::UpName {
|
||||
|
||||
@@ -89,6 +89,7 @@ pub enum Token {
|
||||
When,
|
||||
Trace,
|
||||
Validator,
|
||||
Via,
|
||||
}
|
||||
|
||||
impl fmt::Display for Token {
|
||||
@@ -176,6 +177,7 @@ impl fmt::Display for Token {
|
||||
Token::Test => "test",
|
||||
Token::Fail => "fail",
|
||||
Token::Validator => "validator",
|
||||
Token::Via => "via",
|
||||
};
|
||||
write!(f, "\"{s}\"")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user