Use double-quotes for utf-8 bytearrays, and @"..." for string literals

The core observation is that **in the context of Aiken** (i.e. on-chain logic)
  people do not generally want to use String. Instead, they want
  bytearrays.

  So, it should be easy to produce bytearrays when needed and it should
  be the default. Before this commit, `"foo"` would parse as a `String`.
  Now, it parses as a `ByteArray`, whose bytes are the UTF-8 bytes
  encoding of "foo".

  Now, to make this change really "fool-proof", we now want to:

  - [ ] Emit a parse error if we parse a UTF-8 bytearray literal in
    place where we would expect a `String`. For example, `trace`,
    `error` and `todo` can only be followed by a `String`.

    So when we see something like:

    ```
    trace "foo"
    ```

    we know it's a mistake and we can suggest users to use:

    ```
    trace @"foo"
    ```

    instead.

  - [ ] Emit a warning if we ever see a bytearray literals UTF-8, which
    is either 56 or 64 character long and is a valid hexadecimal string.
    For example:

    ```
    let policy_id = "29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c6"
    ```

    This is _most certainly_ a mistake, as this generates a ByteArray of
    56 bytes, which is effectively the hex-encoding of the provided string.

    In this scenario, we want to warn the user and inform them they probably meant to use:

    ```
    let policy_id = #"29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c6"
    ```
This commit is contained in:
KtorZ 2023-02-17 19:15:13 +01:00
parent 98b89f32e1
commit 53fb821b62
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
7 changed files with 138 additions and 109 deletions

View File

@ -660,7 +660,10 @@ impl<'comments> Formatter<'comments> {
.append("]"), .append("]"),
) )
.group(), .group(),
ByteArrayFormatPreference::Utf8String => todo!(), ByteArrayFormatPreference::Utf8String => nil()
.append("\"")
.append(Document::String(String::from_utf8(bytes.to_vec()).unwrap()))
.append("\""),
} }
} }
@ -767,7 +770,7 @@ impl<'comments> Formatter<'comments> {
} }
fn string<'a>(&self, string: &'a String) -> Document<'a> { fn string<'a>(&self, string: &'a String) -> Document<'a> {
let doc = string.to_doc().surround("\"", "\""); let doc = "@".to_doc().append(string.to_doc().surround("\"", "\""));
if string.contains('\n') { if string.contains('\n') {
doc.force_break() doc.force_break()
} else { } else {

View File

@ -447,9 +447,9 @@ pub fn bytearray_parser(
) )
.map(|token| (ByteArrayFormatPreference::ArrayOfBytes, token)); .map(|token| (ByteArrayFormatPreference::ArrayOfBytes, token));
let bytearray_hexstring_parser = just(Token::Hash) let bytearray_hexstring_parser =
.ignore_then( just(Token::Hash)
select! {Token::String {value} => value}.validate( .ignore_then(select! {Token::ByteString {value} => value}.validate(
|value, span, emit| match hex::decode(value) { |value, span, emit| match hex::decode(value) {
Ok(bytes) => bytes, Ok(bytes) => bytes,
Err(_) => { Err(_) => {
@ -457,11 +457,17 @@ pub fn bytearray_parser(
vec![] vec![]
} }
}, },
), ))
)
.map(|token| (ByteArrayFormatPreference::HexadecimalString, token)); .map(|token| (ByteArrayFormatPreference::HexadecimalString, token));
choice((bytearray_list_parser, bytearray_hexstring_parser)) let bytearray_utf8_parser = select! {Token::ByteString {value} => value.into_bytes() }
.map(|token| (ByteArrayFormatPreference::Utf8String, token));
choice((
bytearray_list_parser,
bytearray_hexstring_parser,
bytearray_utf8_parser,
))
} }
pub fn fn_param_parser() -> impl Parser<Token, ast::UntypedArg, Error = ParseError> { pub fn fn_param_parser() -> impl Parser<Token, ast::UntypedArg, Error = ParseError> {

View File

@ -77,13 +77,21 @@ pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = ParseError> {
.or(just('t').to('\t')), .or(just('t').to('\t')),
); );
let string = just('"') let string = just('@')
.ignore_then(just('"'))
.ignore_then(filter(|c| *c != '\\' && *c != '"').or(escape).repeated()) .ignore_then(filter(|c| *c != '\\' && *c != '"').or(escape).repeated())
.then_ignore(just('"')) .then_ignore(just('"'))
.collect::<String>() .collect::<String>()
.map(|value| Token::String { value }) .map(|value| Token::String { value })
.labelled("string"); .labelled("string");
let bytestring = just('"')
.ignore_then(filter(|c| *c != '\\' && *c != '"').or(escape).repeated())
.then_ignore(just('"'))
.collect::<String>()
.map(|value| Token::ByteString { value })
.labelled("bytestring");
let keyword = text::ident().map(|s: String| match s.as_str() { let keyword = text::ident().map(|s: String| match s.as_str() {
"trace" => Token::Trace, "trace" => Token::Trace,
"error" => Token::ErrorTerm, "error" => Token::ErrorTerm,
@ -158,7 +166,9 @@ pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = ParseError> {
comment_parser(Token::ModuleComment), comment_parser(Token::ModuleComment),
comment_parser(Token::DocComment), comment_parser(Token::DocComment),
comment_parser(Token::Comment), comment_parser(Token::Comment),
choice((ordinal, keyword, int, op, newlines, grouping, string)) choice((
ordinal, keyword, int, op, newlines, grouping, bytestring, string,
))
.or(any().map(Token::Error).validate(|t, span, emit| { .or(any().map(Token::Error).validate(|t, span, emit| {
emit(ParseError::expected_input_found( emit(ParseError::expected_input_found(
span, span,

View File

@ -8,6 +8,7 @@ pub enum Token {
UpName { name: String }, UpName { name: String },
DiscardName { name: String }, DiscardName { name: String },
Int { value: String }, Int { value: String },
ByteString { value: String },
String { value: String }, String { value: String },
// Groupings // Groupings
NewLineLeftParen, // ↳( NewLineLeftParen, // ↳(
@ -97,6 +98,7 @@ impl fmt::Display for Token {
Token::DiscardName { name } => name, Token::DiscardName { name } => name,
Token::Int { value } => value, Token::Int { value } => value,
Token::String { value } => value, Token::String { value } => value,
Token::ByteString { value } => value,
Token::NewLineLeftParen => "↳(", Token::NewLineLeftParen => "↳(",
Token::LeftParen => "(", Token::LeftParen => "(",
Token::RightParen => ")", Token::RightParen => ")",

View File

@ -235,12 +235,12 @@ fn list_pattern_6() {
fn trace_strings() { fn trace_strings() {
let source_code = r#" let source_code = r#"
fn bar() { fn bar() {
"BAR" @"BAR"
} }
test foo() { test foo() {
let msg1 = "FOO" let msg1 = @"FOO"
trace("INLINE") trace(@"INLINE")
trace(msg1) trace(msg1)
trace(bar()) trace(bar())
True True

View File

@ -495,10 +495,14 @@ fn test_bytearray_literals() {
const foo_const_hex = #"666f6f" const foo_const_hex = #"666f6f"
const foo_const_utf8 = "foo"
fn foo() { fn foo() {
let foo_const_array = #[102, 111, 111] let foo_const_array = #[102, 111, 111]
let foo_const_hex = #"666f6f" let foo_const_hex = #"666f6f"
let foo_const_utf8 = "foo"
} }
"#}; "#};

View File

@ -1343,7 +1343,7 @@ fn call() {
#[test] #[test]
fn record_update() { fn record_update() {
let code = indoc! {r#" let code = indoc! {r#"
fn update_name(user: User, name: String) -> User { fn update_name(user: User, name: ByteArray) -> User {
User { ..user, name: "Aiken", age } User { ..user, name: "Aiken", age }
} }
"#}; "#};
@ -1373,60 +1373,61 @@ fn record_update() {
name: "name".to_string(), name: "name".to_string(),
location: Span::new((), 27..31), location: Span::new((), 27..31),
}, },
location: Span::new((), 27..39), location: Span::new((), 27..42),
annotation: Some(ast::Annotation::Constructor { annotation: Some(ast::Annotation::Constructor {
location: Span::new((), 33..39), location: Span::new((), 33..42),
module: None, module: None,
name: "String".to_string(), name: "ByteArray".to_string(),
arguments: vec![], arguments: vec![],
}), }),
tipo: (), tipo: (),
}, },
], ],
body: expr::UntypedExpr::RecordUpdate { body: expr::UntypedExpr::RecordUpdate {
location: Span::new((), 53..88), location: Span::new((), 56..91),
constructor: Box::new(expr::UntypedExpr::Var { constructor: Box::new(expr::UntypedExpr::Var {
location: Span::new((), 53..57), location: Span::new((), 56..60),
name: "User".to_string(), name: "User".to_string(),
}), }),
spread: ast::RecordUpdateSpread { spread: ast::RecordUpdateSpread {
base: Box::new(expr::UntypedExpr::Var { base: Box::new(expr::UntypedExpr::Var {
location: Span::new((), 62..66), location: Span::new((), 65..69),
name: "user".to_string(), name: "user".to_string(),
}), }),
location: Span::new((), 60..66), location: Span::new((), 63..69),
}, },
arguments: vec![ arguments: vec![
ast::UntypedRecordUpdateArg { ast::UntypedRecordUpdateArg {
label: "name".to_string(), label: "name".to_string(),
location: Span::new((), 68..81), location: Span::new((), 71..84),
value: expr::UntypedExpr::String { value: expr::UntypedExpr::ByteArray {
location: Span::new((), 74..81), location: Span::new((), 77..84),
value: "Aiken".to_string(), bytes: String::from("Aiken").into_bytes(),
preferred_format: ast::ByteArrayFormatPreference::Utf8String,
}, },
}, },
ast::UntypedRecordUpdateArg { ast::UntypedRecordUpdateArg {
label: "age".to_string(), label: "age".to_string(),
location: Span::new((), 83..86), location: Span::new((), 86..89),
value: expr::UntypedExpr::Var { value: expr::UntypedExpr::Var {
location: Span::new((), 83..86), location: Span::new((), 86..89),
name: "age".to_string(), name: "age".to_string(),
}, },
}, },
], ],
}, },
doc: None, doc: None,
location: Span::new((), 0..48), location: Span::new((), 0..51),
name: "update_name".to_string(), name: "update_name".to_string(),
public: false, public: false,
return_annotation: Some(ast::Annotation::Constructor { return_annotation: Some(ast::Annotation::Constructor {
location: Span::new((), 44..48), location: Span::new((), 47..51),
module: None, module: None,
name: "User".to_string(), name: "User".to_string(),
arguments: vec![], arguments: vec![],
}), }),
return_type: (), return_type: (),
end_position: 89, end_position: 92,
})], })],
) )
} }
@ -1448,9 +1449,10 @@ fn record_create_labeled() {
ast::CallArg { ast::CallArg {
label: Some("name".to_string()), label: Some("name".to_string()),
location: Span::new((), 23..36), location: Span::new((), 23..36),
value: expr::UntypedExpr::String { value: expr::UntypedExpr::ByteArray {
location: Span::new((), 29..36), location: Span::new((), 29..36),
value: "Aiken".to_string(), bytes: String::from("Aiken").into_bytes(),
preferred_format: ast::ByteArrayFormatPreference::Utf8String,
}, },
}, },
ast::CallArg { ast::CallArg {
@ -1504,9 +1506,10 @@ fn record_create_labeled_with_field_access() {
ast::CallArg { ast::CallArg {
label: Some("name".to_string()), label: Some("name".to_string()),
location: Span::new((), 35..48), location: Span::new((), 35..48),
value: expr::UntypedExpr::String { value: expr::UntypedExpr::ByteArray {
location: Span::new((), 41..48), location: Span::new((), 41..48),
value: "Aiken".to_string(), bytes: String::from("Aiken").into_bytes(),
preferred_format: ast::ByteArrayFormatPreference::Utf8String,
}, },
}, },
ast::CallArg { ast::CallArg {
@ -2492,9 +2495,10 @@ fn clause_guards() {
)), )),
}), }),
}), }),
right: Box::new(ast::ClauseGuard::Constant(ast::Constant::String { right: Box::new(ast::ClauseGuard::Constant(ast::Constant::ByteArray {
location: Span::new((), 178..183), location: Span::new((), 178..183),
value: "str".to_string(), bytes: String::from("str").into_bytes(),
preferred_format: ast::ByteArrayFormatPreference::Utf8String,
})), })),
}), }),
then: expr::UntypedExpr::Var { then: expr::UntypedExpr::Var {
@ -2672,10 +2676,10 @@ fn scope_logical_expression() {
fn trace_expressions() { fn trace_expressions() {
let code = indoc! {r#" let code = indoc! {r#"
fn foo() { fn foo() {
let msg1 = "FOO" let msg1 = @"FOO"
trace "INLINE" trace @"INLINE"
trace msg1 trace msg1
trace string.concat(msg1, "BAR") trace string.concat(msg1, @"BAR")
trace ( 14 + 42 * 1337 ) trace ( 14 + 42 * 1337 )
Void Void
} }
@ -2685,12 +2689,12 @@ fn trace_expressions() {
vec![ast::Definition::Fn(Function { vec![ast::Definition::Fn(Function {
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::Sequence { body: expr::UntypedExpr::Sequence {
location: Span::new((), 13..128), location: Span::new((), 13..131),
expressions: vec![ expressions: vec![
expr::UntypedExpr::Assignment { expr::UntypedExpr::Assignment {
location: Span::new((), 13..29), location: Span::new((), 13..30),
value: Box::new(expr::UntypedExpr::String { value: Box::new(expr::UntypedExpr::String {
location: Span::new((), 24..29), location: Span::new((), 24..30),
value: "FOO".to_string(), value: "FOO".to_string(),
}), }),
pattern: ast::Pattern::Var { pattern: ast::Pattern::Var {
@ -2702,36 +2706,36 @@ fn trace_expressions() {
}, },
expr::UntypedExpr::Trace { expr::UntypedExpr::Trace {
kind: ast::TraceKind::Trace, kind: ast::TraceKind::Trace,
location: Span::new((), 32..128), location: Span::new((), 33..131),
then: Box::new(expr::UntypedExpr::Trace { then: Box::new(expr::UntypedExpr::Trace {
kind: ast::TraceKind::Trace, kind: ast::TraceKind::Trace,
location: Span::new((), 49..128), location: Span::new((), 51..131),
then: Box::new(expr::UntypedExpr::Trace { then: Box::new(expr::UntypedExpr::Trace {
kind: ast::TraceKind::Trace, kind: ast::TraceKind::Trace,
location: Span::new((), 62..128), location: Span::new((), 64..131),
then: Box::new(expr::UntypedExpr::Trace { then: Box::new(expr::UntypedExpr::Trace {
kind: ast::TraceKind::Trace, kind: ast::TraceKind::Trace,
location: Span::new((), 97..128), location: Span::new((), 100..131),
then: Box::new(expr::UntypedExpr::Var { then: Box::new(expr::UntypedExpr::Var {
location: Span::new((), 124..128), location: Span::new((), 127..131),
name: "Void".to_string(), name: "Void".to_string(),
}), }),
text: Box::new(expr::UntypedExpr::BinOp { text: Box::new(expr::UntypedExpr::BinOp {
location: Span::new((), 105..119), location: Span::new((), 108..122),
name: ast::BinOp::AddInt, name: ast::BinOp::AddInt,
left: Box::new(expr::UntypedExpr::Int { left: Box::new(expr::UntypedExpr::Int {
location: Span::new((), 105..107), location: Span::new((), 108..110),
value: "14".to_string(), value: "14".to_string(),
}), }),
right: Box::new(expr::UntypedExpr::BinOp { right: Box::new(expr::UntypedExpr::BinOp {
location: Span::new((), 110..119), location: Span::new((), 113..122),
name: ast::BinOp::MultInt, name: ast::BinOp::MultInt,
left: Box::new(expr::UntypedExpr::Int { left: Box::new(expr::UntypedExpr::Int {
location: Span::new((), 110..112), location: Span::new((), 113..115),
value: "42".to_string(), value: "42".to_string(),
}), }),
right: Box::new(expr::UntypedExpr::Int { right: Box::new(expr::UntypedExpr::Int {
location: Span::new((), 115..119), location: Span::new((), 118..122),
value: "1337".to_string(), value: "1337".to_string(),
}), }),
}), }),
@ -2741,39 +2745,39 @@ fn trace_expressions() {
arguments: vec![ arguments: vec![
ast::CallArg { ast::CallArg {
label: None, label: None,
location: Span::new((), 82..86), location: Span::new((), 84..88),
value: expr::UntypedExpr::Var { value: expr::UntypedExpr::Var {
location: Span::new((), 82..86), location: Span::new((), 84..88),
name: "msg1".to_string(), name: "msg1".to_string(),
}, },
}, },
ast::CallArg { ast::CallArg {
label: None, label: None,
location: Span::new((), 88..93), location: Span::new((), 90..96),
value: expr::UntypedExpr::String { value: expr::UntypedExpr::String {
location: Span::new((), 88..93), location: Span::new((), 90..96),
value: "BAR".to_string(), value: "BAR".to_string(),
}, },
}, },
], ],
fun: Box::new(expr::UntypedExpr::FieldAccess { fun: Box::new(expr::UntypedExpr::FieldAccess {
location: Span::new((), 68..81), location: Span::new((), 70..83),
label: "concat".to_string(), label: "concat".to_string(),
container: Box::new(expr::UntypedExpr::Var { container: Box::new(expr::UntypedExpr::Var {
location: Span::new((), 68..74), location: Span::new((), 70..76),
name: "string".to_string(), name: "string".to_string(),
}), }),
}), }),
location: Span::new((), 68..94), location: Span::new((), 70..97),
}), }),
}), }),
text: Box::new(expr::UntypedExpr::Var { text: Box::new(expr::UntypedExpr::Var {
location: Span::new((), 55..59), location: Span::new((), 57..61),
name: "msg1".to_string(), name: "msg1".to_string(),
}), }),
}), }),
text: Box::new(expr::UntypedExpr::String { text: Box::new(expr::UntypedExpr::String {
location: Span::new((), 38..46), location: Span::new((), 39..48),
value: "INLINE".to_string(), value: "INLINE".to_string(),
}), }),
}, },
@ -2785,7 +2789,7 @@ fn trace_expressions() {
public: false, public: false,
return_annotation: None, return_annotation: None,
return_type: (), return_type: (),
end_position: 129, end_position: 132,
})], })],
) )
} }
@ -2794,7 +2798,7 @@ fn trace_expressions() {
fn parse_keyword_error() { fn parse_keyword_error() {
let code = indoc! {r#" let code = indoc! {r#"
fn foo() { fn foo() {
error "not implemented" error @"not implemented"
} }
fn bar() { fn bar() {
@ -2811,12 +2815,12 @@ fn parse_keyword_error() {
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::Trace { body: expr::UntypedExpr::Trace {
kind: ast::TraceKind::Error, kind: ast::TraceKind::Error,
location: Span::new((), 13..36), location: Span::new((), 13..37),
then: Box::new(expr::UntypedExpr::ErrorTerm { then: Box::new(expr::UntypedExpr::ErrorTerm {
location: Span::new((), 13..36), location: Span::new((), 13..37),
}), }),
text: Box::new(expr::UntypedExpr::String { text: Box::new(expr::UntypedExpr::String {
location: Span::new((), 19..36), location: Span::new((), 19..37),
value: "not implemented".to_string(), value: "not implemented".to_string(),
}), }),
}, },
@ -2826,22 +2830,22 @@ fn parse_keyword_error() {
public: false, public: false,
return_annotation: None, return_annotation: None,
return_type: (), return_type: (),
end_position: 37, end_position: 38,
}), }),
ast::Definition::Fn(Function { ast::Definition::Fn(Function {
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::When { body: expr::UntypedExpr::When {
location: Span::new((), 53..109), location: Span::new((), 54..110),
subjects: vec![expr::UntypedExpr::Var { subjects: vec![expr::UntypedExpr::Var {
location: Span::new((), 58..59), location: Span::new((), 59..60),
name: "x".to_string(), name: "x".to_string(),
}], }],
clauses: vec![ clauses: vec![
ast::Clause { ast::Clause {
location: Span::new((), 71..88), location: Span::new((), 72..89),
pattern: vec![ast::Pattern::Constructor { pattern: vec![ast::Pattern::Constructor {
is_record: false, is_record: false,
location: Span::new((), 71..80), location: Span::new((), 72..81),
name: "Something".to_string(), name: "Something".to_string(),
arguments: vec![], arguments: vec![],
module: None, module: None,
@ -2852,26 +2856,26 @@ fn parse_keyword_error() {
alternative_patterns: vec![], alternative_patterns: vec![],
guard: None, guard: None,
then: expr::UntypedExpr::Var { then: expr::UntypedExpr::Var {
location: Span::new((), 84..88), location: Span::new((), 85..89),
name: "Void".to_string(), name: "Void".to_string(),
}, },
}, },
ast::Clause { ast::Clause {
location: Span::new((), 95..105), location: Span::new((), 96..106),
pattern: vec![ast::Pattern::Discard { pattern: vec![ast::Pattern::Discard {
name: "_".to_string(), name: "_".to_string(),
location: Span::new((), 95..96), location: Span::new((), 96..97),
}], }],
alternative_patterns: vec![], alternative_patterns: vec![],
guard: None, guard: None,
then: expr::UntypedExpr::Trace { then: expr::UntypedExpr::Trace {
kind: ast::TraceKind::Error, kind: ast::TraceKind::Error,
location: Span::new((), 100..105), location: Span::new((), 101..106),
then: Box::new(expr::UntypedExpr::ErrorTerm { then: Box::new(expr::UntypedExpr::ErrorTerm {
location: Span::new((), 100..105), location: Span::new((), 101..106),
}), }),
text: Box::new(expr::UntypedExpr::String { text: Box::new(expr::UntypedExpr::String {
location: Span::new((), 100..105), location: Span::new((), 101..106),
value: "aiken::error".to_string(), value: "aiken::error".to_string(),
}), }),
}, },
@ -2879,12 +2883,12 @@ fn parse_keyword_error() {
], ],
}, },
doc: None, doc: None,
location: Span::new((), 40..48), location: Span::new((), 41..49),
name: "bar".to_string(), name: "bar".to_string(),
public: false, public: false,
return_annotation: None, return_annotation: None,
return_type: (), return_type: (),
end_position: 110, end_position: 111,
}), }),
], ],
) )
@ -2894,7 +2898,7 @@ fn parse_keyword_error() {
fn parse_keyword_todo() { fn parse_keyword_todo() {
let code = indoc! {r#" let code = indoc! {r#"
fn foo() { fn foo() {
todo "not implemented" todo @"not implemented"
} }
fn bar() { fn bar() {
@ -2912,12 +2916,12 @@ fn parse_keyword_todo() {
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::Trace { body: expr::UntypedExpr::Trace {
kind: ast::TraceKind::Todo, kind: ast::TraceKind::Todo,
location: Span::new((), 13..35), location: Span::new((), 13..36),
then: Box::new(expr::UntypedExpr::ErrorTerm { then: Box::new(expr::UntypedExpr::ErrorTerm {
location: Span::new((), 13..35), location: Span::new((), 13..36),
}), }),
text: Box::new(expr::UntypedExpr::String { text: Box::new(expr::UntypedExpr::String {
location: Span::new((), 18..35), location: Span::new((), 18..36),
value: "not implemented".to_string(), value: "not implemented".to_string(),
}), }),
}, },
@ -2927,22 +2931,22 @@ fn parse_keyword_todo() {
public: false, public: false,
return_annotation: None, return_annotation: None,
return_type: (), return_type: (),
end_position: 36, end_position: 37,
}), }),
ast::Definition::Fn(Function { ast::Definition::Fn(Function {
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::When { body: expr::UntypedExpr::When {
location: Span::new((), 52..120), location: Span::new((), 53..121),
subjects: vec![expr::UntypedExpr::Var { subjects: vec![expr::UntypedExpr::Var {
location: Span::new((), 57..58), location: Span::new((), 58..59),
name: "x".to_string(), name: "x".to_string(),
}], }],
clauses: vec![ clauses: vec![
ast::Clause { ast::Clause {
location: Span::new((), 70..81), location: Span::new((), 71..82),
pattern: vec![ast::Pattern::Constructor { pattern: vec![ast::Pattern::Constructor {
is_record: false, is_record: false,
location: Span::new((), 70..73), location: Span::new((), 71..74),
name: "Foo".to_string(), name: "Foo".to_string(),
arguments: vec![], arguments: vec![],
module: None, module: None,
@ -2954,21 +2958,21 @@ fn parse_keyword_todo() {
guard: None, guard: None,
then: expr::UntypedExpr::Trace { then: expr::UntypedExpr::Trace {
kind: ast::TraceKind::Todo, kind: ast::TraceKind::Todo,
location: Span::new((), 77..81), location: Span::new((), 78..82),
then: Box::new(expr::UntypedExpr::ErrorTerm { then: Box::new(expr::UntypedExpr::ErrorTerm {
location: Span::new((), 77..81), location: Span::new((), 78..82),
}), }),
text: Box::new(expr::UntypedExpr::String { text: Box::new(expr::UntypedExpr::String {
location: Span::new((), 77..81), location: Span::new((), 78..82),
value: "aiken::todo".to_string(), value: "aiken::todo".to_string(),
}), }),
}, },
}, },
ast::Clause { ast::Clause {
location: Span::new((), 88..99), location: Span::new((), 89..100),
pattern: vec![ast::Pattern::Constructor { pattern: vec![ast::Pattern::Constructor {
is_record: false, is_record: false,
location: Span::new((), 88..91), location: Span::new((), 89..92),
name: "Bar".to_string(), name: "Bar".to_string(),
arguments: vec![], arguments: vec![],
module: None, module: None,
@ -2979,32 +2983,32 @@ fn parse_keyword_todo() {
alternative_patterns: vec![], alternative_patterns: vec![],
guard: None, guard: None,
then: expr::UntypedExpr::Var { then: expr::UntypedExpr::Var {
location: Span::new((), 95..99), location: Span::new((), 96..100),
name: "True".to_string(), name: "True".to_string(),
}, },
}, },
ast::Clause { ast::Clause {
location: Span::new((), 106..116), location: Span::new((), 107..117),
pattern: vec![ast::Pattern::Discard { pattern: vec![ast::Pattern::Discard {
name: "_".to_string(), name: "_".to_string(),
location: Span::new((), 106..107), location: Span::new((), 107..108),
}], }],
alternative_patterns: vec![], alternative_patterns: vec![],
guard: None, guard: None,
then: expr::UntypedExpr::Var { then: expr::UntypedExpr::Var {
location: Span::new((), 111..116), location: Span::new((), 112..117),
name: "False".to_string(), name: "False".to_string(),
}, },
}, },
], ],
}, },
doc: None, doc: None,
location: Span::new((), 39..47), location: Span::new((), 40..48),
name: "bar".to_string(), name: "bar".to_string(),
public: false, public: false,
return_annotation: None, return_annotation: None,
return_type: (), return_type: (),
end_position: 121, end_position: 122,
}), }),
], ],
) )