Fix dict spreading in dict literal

This commit is contained in:
harupy 2023-01-15 13:01:59 +09:00
parent 163cb5cd67
commit 52d2e25601
4 changed files with 124 additions and 37 deletions

View file

@ -195,7 +195,7 @@ pub enum ExprKind<U = ()> {
orelse: Box<Expr<U>>,
},
Dict {
keys: Vec<Expr<U>>,
keys: Vec<Option<Expr<U>>>,
values: Vec<Expr<U>>,
},
Set {

View file

@ -1138,42 +1138,42 @@ Atom<Goal>: ast::Expr = {
<location:@L> "{" <e:DictLiteralValues?> "}" <end_location:@R> => {
let pairs = e.unwrap_or_default();
let (keys, values) = match pairs.iter().position(|(k,_)| k.is_none()) {
Some(unpack_idx) => {
let mut pairs = pairs;
let (keys, mut values): (_, Vec<_>) = pairs.drain(..unpack_idx).map(|(k, v)| (*k.unwrap(), v)).unzip();
fn build_map(items: &mut Vec<(ast::Expr, ast::Expr)>) -> ast::Expr {
let location = items[0].0.location;
let end_location = items[0].0.end_location;
let (keys, values) = items.drain(..).unzip();
ast::Expr {
location,
end_location,
custom: (),
node: ast::ExprKind::Dict { keys, values }
}
}
let mut items = Vec::new();
for (key, value) in pairs.into_iter() {
if let Some(key) = key {
items.push((*key, value));
continue;
}
if !items.is_empty() {
values.push(build_map(&mut items));
}
values.push(value);
}
if !items.is_empty() {
values.push(build_map(&mut items));
}
(keys, values)
},
None => pairs.into_iter().map(|(k, v)| (*k.unwrap(), v)).unzip()
};
// let (keys, values) = match pairs.iter().position(|(k,_)| k.is_none()) {
// Some(unpack_idx) => {
// let mut pairs = pairs;
// let (keys, mut values): (_, Vec<_>) = pairs.drain(..unpack_idx).map(|(k, v)| (*k.unwrap(), v)).unzip();
//
// fn build_map(items: &mut Vec<(ast::Expr, ast::Expr)>) -> ast::Expr {
// let location = items[0].0.location;
// let end_location = items[0].0.end_location;
// let (keys, values) = items.drain(..).unzip();
// ast::Expr {
// location,
// end_location,
// custom: (),
// node: ast::ExprKind::Dict { keys, values }
// }
// }
//
// let mut items = Vec::new();
// for (key, value) in pairs.into_iter() {
// if let Some(key) = key {
// items.push((*key, value));
// continue;
// }
// if !items.is_empty() {
// values.push(build_map(&mut items));
// }
// values.push(value);
// }
// if !items.is_empty() {
// values.push(build_map(&mut items));
// }
// (keys, values)
// },
// None => pairs.into_iter().map(|(k, v)| (k, v)).unzip()
// };
let (keys, values) = pairs.into_iter().map(|(k, v)| (k.map(|x| *x), v)).unzip();
ast::Expr {
location,
end_location: Some(end_location),

View file

@ -309,4 +309,10 @@ with (0 as a, 1 as b,): pass
assert!(parse_program(source, "<test>").is_err());
}
}
#[test]
fn test_dict_containing_spread() {
let parse_ast = parse_expression(r#"{"k": "v", **d}"#, "<test>").unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
}

View file

@ -0,0 +1,81 @@
---
source: compiler/parser/src/parser.rs
expression: parse_ast
---
Located {
location: Location {
row: 1,
column: 0,
},
end_location: Some(
Location {
row: 1,
column: 15,
},
),
custom: (),
node: Dict {
keys: [
Some(
Located {
location: Location {
row: 1,
column: 1,
},
end_location: Some(
Location {
row: 1,
column: 4,
},
),
custom: (),
node: Constant {
value: Str(
"k",
),
kind: None,
},
},
),
None,
],
values: [
Located {
location: Location {
row: 1,
column: 6,
},
end_location: Some(
Location {
row: 1,
column: 9,
},
),
custom: (),
node: Constant {
value: Str(
"v",
),
kind: None,
},
},
Located {
location: Location {
row: 1,
column: 13,
},
end_location: Some(
Location {
row: 1,
column: 14,
},
),
custom: (),
node: Name {
id: "d",
ctx: Load,
},
},
],
},
}