test(parser): type alias, anon fn, record update and more

This commit is contained in:
rvcas 2023-07-03 16:44:18 -04:00
parent bd8c13c372
commit a75bcff5c8
No known key found for this signature in database
GPG Key ID: C09B64E263F7D68C
28 changed files with 453 additions and 713 deletions

View File

@ -89,3 +89,13 @@ pub fn parser() -> impl Parser<Token, ast::Annotation, Error = ParseError> {
)) ))
}) })
} }
#[cfg(test)]
mod tests {
use crate::assert_annotation;
#[test]
fn type_annotation_with_module_prefix() {
assert_annotation!("aiken.Option<Int>");
}
}

View File

@ -87,3 +87,26 @@ pub fn param(is_validator_param: bool) -> impl Parser<Token, ast::UntypedArg, Er
arg_name, arg_name,
}) })
} }
#[cfg(test)]
mod tests {
use crate::assert_definition;
#[test]
fn function_empty() {
assert_definition!(
r#"
pub fn run() {}
"#
);
}
#[test]
fn function_non_public() {
assert_definition!(
r#"
fn run() {}
"#
);
}
}

View File

@ -0,0 +1,45 @@
---
source: crates/aiken-lang/src/parser/definition/test.rs
description: "Code:\n\n!test invalid_inputs() {\n expect True = False\n\n False\n}\n"
---
Test(
Function {
arguments: [],
body: Sequence {
location: 27..55,
expressions: [
Assignment {
location: 27..46,
value: Var {
location: 41..46,
name: "False",
},
pattern: Constructor {
is_record: false,
location: 34..38,
name: "True",
arguments: [],
module: None,
constructor: (),
with_spread: false,
tipo: (),
},
kind: Expect,
annotation: None,
},
Var {
location: 50..55,
name: "False",
},
],
},
doc: None,
location: 0..22,
name: "invalid_inputs",
public: false,
return_annotation: None,
return_type: (),
end_position: 56,
can_error: true,
},
)

View File

@ -0,0 +1,28 @@
---
source: crates/aiken-lang/src/parser/definition/function.rs
description: "Code:\n\npub fn run() {}\n"
---
Fn(
Function {
arguments: [],
body: Trace {
kind: Todo,
location: 0..15,
then: ErrorTerm {
location: 0..15,
},
text: String {
location: 0..15,
value: "aiken::todo",
},
},
doc: None,
location: 0..12,
name: "run",
public: true,
return_annotation: None,
return_type: (),
end_position: 14,
can_error: true,
},
)

View File

@ -0,0 +1,28 @@
---
source: crates/aiken-lang/src/parser/definition/function.rs
description: "Code:\n\nfn run() {}\n"
---
Fn(
Function {
arguments: [],
body: Trace {
kind: Todo,
location: 0..11,
then: ErrorTerm {
location: 0..11,
},
text: String {
location: 0..11,
value: "aiken::todo",
},
},
doc: None,
location: 0..8,
name: "run",
public: false,
return_annotation: None,
return_type: (),
end_position: 10,
can_error: true,
},
)

View File

@ -0,0 +1,20 @@
---
source: crates/aiken-lang/src/parser/definition/type_alias.rs
description: "Code:\n\ntype Thing = Int"
---
TypeAlias(
TypeAlias {
alias: "Thing",
annotation: Constructor {
location: 13..16,
module: None,
name: "Int",
arguments: [],
},
doc: None,
location: 0..16,
parameters: [],
public: false,
tipo: (),
},
)

View File

@ -0,0 +1,20 @@
---
source: crates/aiken-lang/src/parser/definition/type_alias.rs
description: "Code:\n\npub type Me = String"
---
TypeAlias(
TypeAlias {
alias: "Me",
annotation: Constructor {
location: 14..20,
module: None,
name: "String",
arguments: [],
},
doc: None,
location: 0..20,
parameters: [],
public: true,
tipo: (),
},
)

View File

@ -0,0 +1,31 @@
---
source: crates/aiken-lang/src/parser/definition/type_alias.rs
description: "Code:\n\ntype RoyaltyToken = (PolicyId, AssetName)"
---
TypeAlias(
TypeAlias {
alias: "RoyaltyToken",
annotation: Tuple {
location: 20..41,
elems: [
Constructor {
location: 21..29,
module: None,
name: "PolicyId",
arguments: [],
},
Constructor {
location: 31..40,
module: None,
name: "AssetName",
arguments: [],
},
],
},
doc: None,
location: 0..41,
parameters: [],
public: false,
tipo: (),
},
)

View File

@ -35,3 +35,21 @@ pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError
}) })
}) })
} }
#[cfg(test)]
mod tests {
use crate::assert_definition;
#[test]
fn test_fail() {
assert_definition!(
r#"
!test invalid_inputs() {
expect True = False
False
}
"#
);
}
}

View File

@ -23,3 +23,32 @@ pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError
}) })
}) })
} }
#[cfg(test)]
mod tests {
use crate::assert_definition;
#[test]
fn type_alias_tuple() {
assert_definition!(
r#"
type RoyaltyToken = (PolicyId, AssetName)"#
);
}
#[test]
fn type_alias_basic() {
assert_definition!(
r#"
type Thing = Int"#
);
}
#[test]
fn type_alias_pub() {
assert_definition!(
r#"
pub type Me = String"#
);
}
}

View File

@ -54,3 +54,13 @@ pub fn params() -> impl Parser<Token, ast::UntypedArg, Error = ParseError> {
arg_name, arg_name,
}) })
} }
#[cfg(test)]
mod tests {
use crate::assert_expr;
#[test]
fn anonymous_function_basic() {
assert_expr!(r#"fn (a: Int) -> Int { a + 1 }"#);
}
}

View File

@ -43,3 +43,13 @@ fn assignment(
}, },
) )
} }
#[cfg(test)]
mod tests {
use crate::assert_expr;
#[test]
fn let_bindings() {
assert_expr!(r#"let thing = [ 1, 2, a ]"#);
}
}

View File

@ -84,3 +84,13 @@ pub fn parser(
} }
}) })
} }
#[cfg(test)]
mod tests {
use crate::assert_expr;
#[test]
fn record_update_basic() {
assert_expr!(r#"User { ..user, name: "Aiken", age }"#);
}
}

View File

@ -0,0 +1,51 @@
---
source: crates/aiken-lang/src/parser/expr/anonymous_function.rs
description: "Code:\n\nfn (a: Int) -> Int { a + 1 }"
---
Fn {
location: 0..28,
fn_style: Plain,
arguments: [
Arg {
arg_name: Named {
name: "a",
label: "a",
location: 4..5,
is_validator_param: false,
},
location: 4..10,
annotation: Some(
Constructor {
location: 7..10,
module: None,
name: "Int",
arguments: [],
},
),
tipo: (),
},
],
body: BinOp {
location: 21..26,
name: AddInt,
left: Var {
location: 21..22,
name: "a",
},
right: Int {
location: 25..26,
value: "1",
base: Decimal {
numeric_underscore: false,
},
},
},
return_annotation: Some(
Constructor {
location: 15..18,
module: None,
name: "Int",
arguments: [],
},
),
}

View File

@ -0,0 +1,37 @@
---
source: crates/aiken-lang/src/parser/expr/assignment.rs
description: "Code:\n\nlet thing = [ 1, 2, a ]"
---
Assignment {
location: 0..23,
value: List {
location: 12..23,
elements: [
Int {
location: 14..15,
value: "1",
base: Decimal {
numeric_underscore: false,
},
},
Int {
location: 17..18,
value: "2",
base: Decimal {
numeric_underscore: false,
},
},
Var {
location: 20..21,
name: "a",
},
],
tail: None,
},
pattern: Var {
location: 4..9,
name: "thing",
},
kind: Let,
annotation: None,
}

View File

@ -0,0 +1,43 @@
---
source: crates/aiken-lang/src/parser/expr/record_update.rs
description: "Code:\n\nUser { ..user, name: \"Aiken\", age }"
---
RecordUpdate {
location: 0..35,
constructor: Var {
location: 0..4,
name: "User",
},
spread: RecordUpdateSpread {
base: Var {
location: 9..13,
name: "user",
},
location: 7..13,
},
arguments: [
UntypedRecordUpdateArg {
label: "name",
location: 15..28,
value: ByteArray {
location: 21..28,
bytes: [
65,
105,
107,
101,
110,
],
preferred_format: Utf8String,
},
},
UntypedRecordUpdateArg {
label: "age",
location: 30..33,
value: Var {
location: 30..33,
name: "age",
},
},
],
}

View File

@ -0,0 +1,19 @@
---
source: crates/aiken-lang/src/parser/annotation.rs
description: "Code:\n\naiken.Option<Int>"
---
Constructor {
location: 0..17,
module: Some(
"aiken",
),
name: "Option",
arguments: [
Constructor {
location: 13..16,
module: None,
name: "Int",
arguments: [],
},
],
}

View File

@ -115,6 +115,27 @@ macro_rules! assert_expr {
}; };
} }
#[macro_export]
macro_rules! assert_annotation {
($code:expr) => {
use chumsky::Parser;
let $crate::parser::lexer::LexInfo { tokens, .. } = $crate::parser::lexer::run(indoc::indoc! { $code }).unwrap();
let stream = chumsky::Stream::from_iter($crate::ast::Span::create(tokens.len()), tokens.into_iter());
let result = $crate::parser::annotation().parse(stream).unwrap();
insta::with_settings!({
description => concat!("Code:\n\n", indoc::indoc! { $code }),
prepend_module_to_snapshot => false,
omit_expression => true
}, {
insta::assert_debug_snapshot!(result);
});
};
}
#[macro_export] #[macro_export]
macro_rules! assert_module { macro_rules! assert_module {
($code:expr) => { ($code:expr) => {

View File

@ -1,31 +1,5 @@
use crate::assert_module; use crate::assert_module;
#[test]
fn type_annotation_with_module_prefix() {
assert_module!(
r#"
use aiken
pub fn go() -> aiken.Option<Int> {
False
}
"#
);
}
#[test]
fn test_fail() {
assert_module!(
r#"
!test invalid_inputs() {
expect True = False
False
}
"#
);
}
#[test] #[test]
fn custom_type() { fn custom_type() {
assert_module!( assert_module!(
@ -50,33 +24,6 @@ fn opaque_type() {
); );
} }
#[test]
fn type_alias() {
assert_module!(
r#"
type Thing = Option<Int>
"#
);
}
#[test]
fn pub_type_alias() {
assert_module!(
r#"
pub type Me = Option<String>
"#
);
}
#[test]
fn empty_function() {
assert_module!(
r#"
pub fn run() {}
"#
);
}
#[test] #[test]
fn expect() { fn expect() {
assert_module!( assert_module!(
@ -113,26 +60,6 @@ fn pipeline() {
); );
} }
#[test]
fn let_bindings() {
assert_module!(
r#"
pub fn wow(a: Int) {
let x =
a + 2
|> add_one
|> add_one
let thing = [ 1, 2, a ]
let idk = thing
y
}
"#
);
}
#[test] #[test]
fn block() { fn block() {
assert_module!( assert_module!(
@ -169,19 +96,6 @@ fn when() {
); );
} }
#[test]
fn anonymous_function() {
assert_module!(
r#"
pub fn such() -> Int {
let add_one = fn (a: Int) -> Int { a + 1 }
2 |> add_one
}
"#
);
}
#[test] #[test]
fn field_access() { fn field_access() {
assert_module!( assert_module!(
@ -208,17 +122,6 @@ fn call() {
); );
} }
#[test]
fn record_update() {
assert_module!(
r#"
fn update_name(user: User, name: ByteArray) -> User {
User { ..user, name: "Aiken", age }
}
"#
);
}
#[test] #[test]
fn record_create_labeled() { fn record_create_labeled() {
assert_module!( assert_module!(
@ -344,15 +247,6 @@ fn function_ambiguous_sequence() {
); );
} }
#[test]
fn tuple_type_alias() {
assert_module!(
r#"
type RoyaltyToken = (PolicyId, AssetName)
"#
);
}
#[test] #[test]
fn first_class_binop() { fn first_class_binop() {
assert_module!( assert_module!(

View File

@ -1,109 +0,0 @@
---
source: crates/aiken-lang/src/tests/parser.rs
description: "Code:\n\npub fn such() -> Int {\n let add_one = fn (a: Int) -> Int { a + 1 }\n\n 2 |> add_one\n}\n"
---
Module {
name: "",
docs: [],
type_info: (),
definitions: [
Fn(
Function {
arguments: [],
body: Sequence {
location: 25..83,
expressions: [
Assignment {
location: 25..67,
value: Fn {
location: 39..67,
fn_style: Plain,
arguments: [
Arg {
arg_name: Named {
name: "a",
label: "a",
location: 43..44,
is_validator_param: false,
},
location: 43..49,
annotation: Some(
Constructor {
location: 46..49,
module: None,
name: "Int",
arguments: [],
},
),
tipo: (),
},
],
body: BinOp {
location: 60..65,
name: AddInt,
left: Var {
location: 60..61,
name: "a",
},
right: Int {
location: 64..65,
value: "1",
base: Decimal {
numeric_underscore: false,
},
},
},
return_annotation: Some(
Constructor {
location: 54..57,
module: None,
name: "Int",
arguments: [],
},
),
},
pattern: Var {
location: 29..36,
name: "add_one",
},
kind: Let,
annotation: None,
},
PipeLine {
expressions: [
Int {
location: 71..72,
value: "2",
base: Decimal {
numeric_underscore: false,
},
},
Var {
location: 76..83,
name: "add_one",
},
],
one_liner: true,
},
],
},
doc: None,
location: 0..20,
name: "such",
public: true,
return_annotation: Some(
Constructor {
location: 17..20,
module: None,
name: "Int",
arguments: [],
},
),
return_type: (),
end_position: 84,
can_error: true,
},
),
],
kind: Validator,
}

View File

@ -1,36 +0,0 @@
---
source: crates/aiken-lang/src/tests/parser.rs
description: "Code:\n\npub fn run() {}\n"
---
Module {
name: "",
docs: [],
type_info: (),
definitions: [
Fn(
Function {
arguments: [],
body: Trace {
kind: Todo,
location: 0..15,
then: ErrorTerm {
location: 0..15,
},
text: String {
location: 0..15,
value: "aiken::todo",
},
},
doc: None,
location: 0..12,
name: "run",
public: true,
return_annotation: None,
return_type: (),
end_position: 14,
can_error: true,
},
),
],
kind: Validator,
}

View File

@ -1,53 +0,0 @@
---
source: crates/aiken-lang/src/tests/parser.rs
description: "Code:\n\n!test invalid_inputs() {\n expect True = False\n\n False\n}\n"
---
Module {
name: "",
docs: [],
type_info: (),
definitions: [
Test(
Function {
arguments: [],
body: Sequence {
location: 27..55,
expressions: [
Assignment {
location: 27..46,
value: Var {
location: 41..46,
name: "False",
},
pattern: Constructor {
is_record: false,
location: 34..38,
name: "True",
arguments: [],
module: None,
constructor: (),
with_spread: false,
tipo: (),
},
kind: Expect,
annotation: None,
},
Var {
location: 50..55,
name: "False",
},
],
},
doc: None,
location: 0..22,
name: "invalid_inputs",
public: false,
return_annotation: None,
return_type: (),
end_position: 56,
can_error: true,
},
),
],
kind: Validator,
}

View File

@ -1,136 +0,0 @@
---
source: crates/aiken-lang/src/tests/parser.rs
description: "Code:\n\npub fn wow(a: Int) {\n let x =\n a + 2\n |> add_one\n |> add_one\n\n let thing = [ 1, 2, a ]\n\n let idk = thing\n\n y\n}\n"
---
Module {
name: "",
docs: [],
type_info: (),
definitions: [
Fn(
Function {
arguments: [
Arg {
arg_name: Named {
name: "a",
label: "a",
location: 11..12,
is_validator_param: false,
},
location: 11..17,
annotation: Some(
Constructor {
location: 14..17,
module: None,
name: "Int",
arguments: [],
},
),
tipo: (),
},
],
body: Sequence {
location: 23..121,
expressions: [
Assignment {
location: 23..70,
value: PipeLine {
expressions: [
BinOp {
location: 35..40,
name: AddInt,
left: Var {
location: 35..36,
name: "a",
},
right: Int {
location: 39..40,
value: "2",
base: Decimal {
numeric_underscore: false,
},
},
},
Var {
location: 48..55,
name: "add_one",
},
Var {
location: 63..70,
name: "add_one",
},
],
one_liner: false,
},
pattern: Var {
location: 27..28,
name: "x",
},
kind: Let,
annotation: None,
},
Assignment {
location: 74..97,
value: List {
location: 86..97,
elements: [
Int {
location: 88..89,
value: "1",
base: Decimal {
numeric_underscore: false,
},
},
Int {
location: 91..92,
value: "2",
base: Decimal {
numeric_underscore: false,
},
},
Var {
location: 94..95,
name: "a",
},
],
tail: None,
},
pattern: Var {
location: 78..83,
name: "thing",
},
kind: Let,
annotation: None,
},
Assignment {
location: 101..116,
value: Var {
location: 111..116,
name: "thing",
},
pattern: Var {
location: 105..108,
name: "idk",
},
kind: Let,
annotation: None,
},
Var {
location: 120..121,
name: "y",
},
],
},
doc: None,
location: 0..18,
name: "wow",
public: true,
return_annotation: None,
return_type: (),
end_position: 122,
can_error: true,
},
),
],
kind: Validator,
}

View File

@ -1,35 +0,0 @@
---
source: crates/aiken-lang/src/tests/parser.rs
description: "Code:\n\npub type Me = Option<String>\n"
---
Module {
name: "",
docs: [],
type_info: (),
definitions: [
TypeAlias(
TypeAlias {
alias: "Me",
annotation: Constructor {
location: 14..28,
module: None,
name: "Option",
arguments: [
Constructor {
location: 21..27,
module: None,
name: "String",
arguments: [],
},
],
},
doc: None,
location: 0..28,
parameters: [],
public: true,
tipo: (),
},
),
],
kind: Validator,
}

View File

@ -1,108 +0,0 @@
---
source: crates/aiken-lang/src/tests/parser.rs
description: "Code:\n\nfn update_name(user: User, name: ByteArray) -> User {\n User { ..user, name: \"Aiken\", age }\n}\n"
---
Module {
name: "",
docs: [],
type_info: (),
definitions: [
Fn(
Function {
arguments: [
Arg {
arg_name: Named {
name: "user",
label: "user",
location: 15..19,
is_validator_param: false,
},
location: 15..25,
annotation: Some(
Constructor {
location: 21..25,
module: None,
name: "User",
arguments: [],
},
),
tipo: (),
},
Arg {
arg_name: Named {
name: "name",
label: "name",
location: 27..31,
is_validator_param: false,
},
location: 27..42,
annotation: Some(
Constructor {
location: 33..42,
module: None,
name: "ByteArray",
arguments: [],
},
),
tipo: (),
},
],
body: RecordUpdate {
location: 56..91,
constructor: Var {
location: 56..60,
name: "User",
},
spread: RecordUpdateSpread {
base: Var {
location: 65..69,
name: "user",
},
location: 63..69,
},
arguments: [
UntypedRecordUpdateArg {
label: "name",
location: 71..84,
value: ByteArray {
location: 77..84,
bytes: [
65,
105,
107,
101,
110,
],
preferred_format: Utf8String,
},
},
UntypedRecordUpdateArg {
label: "age",
location: 86..89,
value: Var {
location: 86..89,
name: "age",
},
},
],
},
doc: None,
location: 0..51,
name: "update_name",
public: false,
return_annotation: Some(
Constructor {
location: 47..51,
module: None,
name: "User",
arguments: [],
},
),
return_type: (),
end_position: 92,
can_error: true,
},
),
],
kind: Validator,
}

View File

@ -1,39 +0,0 @@
---
source: crates/aiken-lang/src/tests/parser.rs
description: "Code:\n\ntype RoyaltyToken = (PolicyId, AssetName)\n"
---
Module {
name: "",
docs: [],
type_info: (),
definitions: [
TypeAlias(
TypeAlias {
alias: "RoyaltyToken",
annotation: Tuple {
location: 20..41,
elems: [
Constructor {
location: 21..29,
module: None,
name: "PolicyId",
arguments: [],
},
Constructor {
location: 31..40,
module: None,
name: "AssetName",
arguments: [],
},
],
},
doc: None,
location: 0..41,
parameters: [],
public: false,
tipo: (),
},
),
],
kind: Validator,
}

View File

@ -1,35 +0,0 @@
---
source: crates/aiken-lang/src/tests/parser.rs
description: "Code:\n\ntype Thing = Option<Int>\n"
---
Module {
name: "",
docs: [],
type_info: (),
definitions: [
TypeAlias(
TypeAlias {
alias: "Thing",
annotation: Constructor {
location: 13..24,
module: None,
name: "Option",
arguments: [
Constructor {
location: 20..23,
module: None,
name: "Int",
arguments: [],
},
],
},
doc: None,
location: 0..24,
parameters: [],
public: false,
tipo: (),
},
),
],
kind: Validator,
}

View File

@ -1,56 +0,0 @@
---
source: crates/aiken-lang/src/tests/parser.rs
description: "Code:\n\nuse aiken\n\npub fn go() -> aiken.Option<Int> {\n False\n}\n"
---
Module {
name: "",
docs: [],
type_info: (),
definitions: [
Use(
Use {
as_name: None,
location: 0..9,
module: [
"aiken",
],
package: (),
unqualified: [],
},
),
Fn(
Function {
arguments: [],
body: Var {
location: 48..53,
name: "False",
},
doc: None,
location: 11..43,
name: "go",
public: true,
return_annotation: Some(
Constructor {
location: 26..43,
module: Some(
"aiken",
),
name: "Option",
arguments: [
Constructor {
location: 39..42,
module: None,
name: "Int",
arguments: [],
},
],
},
),
return_type: (),
end_position: 54,
can_error: true,
},
),
],
kind: Validator,
}