Fix record shorthand causing parsing ambiguity in if/else expressions.
Fixes #735.
This commit is contained in:
parent
1dea348a2e
commit
f379039efc
|
@ -13,6 +13,7 @@
|
||||||
- **uplc**: uplc `Constant::Data` formatting
|
- **uplc**: uplc `Constant::Data` formatting
|
||||||
- **aiken-lang**: empty records properly parse as record sugar
|
- **aiken-lang**: empty records properly parse as record sugar
|
||||||
- **aiken-lang**: escape sequences are now properly preserved after formatting
|
- **aiken-lang**: escape sequences are now properly preserved after formatting
|
||||||
|
- **aiken-lang**: fixed parser ambiguity when using record constructor in if conditions followed by single-line var expressions #735
|
||||||
- **aiken-project**: when a module name has a hyphen we should behave like rust and force an underscore
|
- **aiken-project**: when a module name has a hyphen we should behave like rust and force an underscore
|
||||||
|
|
||||||
## v1.0.16-alpha - 2023-08-24
|
## v1.0.16-alpha - 2023-08-24
|
||||||
|
|
|
@ -24,15 +24,24 @@ mod tests {
|
||||||
use crate::assert_expr;
|
use crate::assert_expr;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn block_basic() {
|
fn block_let() {
|
||||||
assert_expr!(
|
assert_expr!(
|
||||||
r#"
|
r#"
|
||||||
let b = {
|
let b = {
|
||||||
let x = 4
|
let x = 4
|
||||||
|
|
||||||
x + 5
|
x + 5
|
||||||
}
|
}
|
||||||
"#
|
"#
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn block_single() {
|
||||||
|
assert_expr!(
|
||||||
|
r#"{
|
||||||
|
foo
|
||||||
|
}
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,4 +71,19 @@ mod tests {
|
||||||
"#
|
"#
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn if_else_ambiguous_record() {
|
||||||
|
assert_expr!(
|
||||||
|
r#"
|
||||||
|
if ec1 == Infinity {
|
||||||
|
ec2
|
||||||
|
} else if ec1 == Foo { foo } {
|
||||||
|
ec1
|
||||||
|
} else {
|
||||||
|
Infinity
|
||||||
|
}
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,38 @@ pub fn parser(
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
))
|
))
|
||||||
|
// NOTE: There's an ambiguity when the record shorthand syntax is used
|
||||||
|
// from within an if-else statement in the case of single-variable if-branch.
|
||||||
|
//
|
||||||
|
// For example, imagine the following:
|
||||||
|
//
|
||||||
|
// ```
|
||||||
|
// if season == Summer {
|
||||||
|
// foo
|
||||||
|
// } else {
|
||||||
|
// bar
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// Without that next odd parser combinator, the parser would parse:
|
||||||
|
//
|
||||||
|
// ```
|
||||||
|
// if season == Summer { foo }
|
||||||
|
// else {
|
||||||
|
// bar
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// And immediately choke on the next `else` because the if-branch body has
|
||||||
|
// already been consumed and interpreted as a record definition. So the next
|
||||||
|
// combinator ensures that we give priority back to an if-then statement rather
|
||||||
|
// than to the record definition.
|
||||||
|
.then_ignore(
|
||||||
|
just(Token::RightBrace)
|
||||||
|
.ignore_then(just(Token::Else))
|
||||||
|
.not()
|
||||||
|
.rewind(),
|
||||||
|
)
|
||||||
.map(|(value, name)| ast::CallArg {
|
.map(|(value, name)| ast::CallArg {
|
||||||
location: value.location(),
|
location: value.location(),
|
||||||
value,
|
value,
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
---
|
||||||
|
source: crates/aiken-lang/src/parser/expr/block.rs
|
||||||
|
description: "Code:\n\nlet b = {\n let x = 4\n x + 5\n}\n"
|
||||||
|
---
|
||||||
|
Assignment {
|
||||||
|
location: 0..31,
|
||||||
|
value: Sequence {
|
||||||
|
location: 12..29,
|
||||||
|
expressions: [
|
||||||
|
Assignment {
|
||||||
|
location: 12..21,
|
||||||
|
value: UInt {
|
||||||
|
location: 20..21,
|
||||||
|
value: "4",
|
||||||
|
base: Decimal {
|
||||||
|
numeric_underscore: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pattern: Var {
|
||||||
|
location: 16..17,
|
||||||
|
name: "x",
|
||||||
|
},
|
||||||
|
kind: Let,
|
||||||
|
annotation: None,
|
||||||
|
},
|
||||||
|
BinOp {
|
||||||
|
location: 24..29,
|
||||||
|
name: AddInt,
|
||||||
|
left: Var {
|
||||||
|
location: 24..25,
|
||||||
|
name: "x",
|
||||||
|
},
|
||||||
|
right: UInt {
|
||||||
|
location: 28..29,
|
||||||
|
value: "5",
|
||||||
|
base: Decimal {
|
||||||
|
numeric_underscore: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
pattern: Var {
|
||||||
|
location: 4..5,
|
||||||
|
name: "b",
|
||||||
|
},
|
||||||
|
kind: Let,
|
||||||
|
annotation: None,
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
source: crates/aiken-lang/src/parser/expr/block.rs
|
||||||
|
description: "Code:\n\n{\nfoo\n}\n"
|
||||||
|
---
|
||||||
|
Var {
|
||||||
|
location: 2..5,
|
||||||
|
name: "foo",
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
---
|
||||||
|
source: crates/aiken-lang/src/parser/expr/if_else.rs
|
||||||
|
description: "Code:\n\nif ec1 == Infinity {\n ec2\n} else if ec1 == Foo { foo } {\n ec1\n} else {\n Infinity\n}\n"
|
||||||
|
---
|
||||||
|
If {
|
||||||
|
location: 0..85,
|
||||||
|
branches: [
|
||||||
|
IfBranch {
|
||||||
|
condition: BinOp {
|
||||||
|
location: 3..18,
|
||||||
|
name: Eq,
|
||||||
|
left: Var {
|
||||||
|
location: 3..6,
|
||||||
|
name: "ec1",
|
||||||
|
},
|
||||||
|
right: Var {
|
||||||
|
location: 10..18,
|
||||||
|
name: "Infinity",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Var {
|
||||||
|
location: 23..26,
|
||||||
|
name: "ec2",
|
||||||
|
},
|
||||||
|
location: 3..28,
|
||||||
|
},
|
||||||
|
IfBranch {
|
||||||
|
condition: BinOp {
|
||||||
|
location: 37..55,
|
||||||
|
name: Eq,
|
||||||
|
left: Var {
|
||||||
|
location: 37..40,
|
||||||
|
name: "ec1",
|
||||||
|
},
|
||||||
|
right: Call {
|
||||||
|
arguments: [
|
||||||
|
CallArg {
|
||||||
|
label: Some(
|
||||||
|
"foo",
|
||||||
|
),
|
||||||
|
location: 50..53,
|
||||||
|
value: Var {
|
||||||
|
location: 50..53,
|
||||||
|
name: "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
fun: Var {
|
||||||
|
location: 44..47,
|
||||||
|
name: "Foo",
|
||||||
|
},
|
||||||
|
location: 44..55,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Var {
|
||||||
|
location: 60..63,
|
||||||
|
name: "ec1",
|
||||||
|
},
|
||||||
|
location: 37..65,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
final_else: Var {
|
||||||
|
location: 75..83,
|
||||||
|
name: "Infinity",
|
||||||
|
},
|
||||||
|
}
|
Loading…
Reference in New Issue