Skip to content

Commit bea97cd

Browse files
Implement CPython-like implicit string concatenation in parser (RustPython#4097)
1 parent e44ccb0 commit bea97cd

16 files changed

+544
-27
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

parser/Cargo.toml

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,23 @@ license = "MIT"
99
edition = "2021"
1010

1111
[build-dependencies]
12-
tiny-keccak = { version = "2", features = ["sha3"] }
13-
phf_codegen = "0.10"
14-
lalrpop = { version = "0.19.8", optional = true }
1512
anyhow = "1.0.45"
13+
lalrpop = { version = "0.19.8", optional = true }
14+
phf_codegen = "0.10"
15+
tiny-keccak = { version = "2", features = ["sha3"] }
1616

1717
[dependencies]
18-
rustpython-ast = { path = "../ast" }
18+
ahash = "0.7.6"
19+
itertools = "0.10.3"
1920
lalrpop-util = "0.19.8"
2021
log = "0.4.16"
2122
num-bigint = "0.4.3"
2223
num-traits = "0.2.14"
24+
phf = "0.10.1"
25+
rustpython-ast = { path = "../ast" }
2326
unic-emoji-char = "0.9.0"
2427
unic-ucd-ident = "0.9.0"
2528
unicode_names2 = "0.5.0"
26-
phf = "0.10.1"
27-
ahash = "0.7.6"
2829

2930
[dev-dependencies]
3031
insta = "1.14.0"

parser/python.lalrpop

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
use crate::{
77
ast,
88
error::{LexicalError, LexicalErrorType},
9-
fstring::parse_located_fstring,
109
function::{ArgumentList, parse_args, parse_params},
1110
lexer,
11+
string::parse_strings,
1212
token::StringKind
1313
};
1414
use num_bigint::BigInt;
@@ -961,26 +961,7 @@ SliceOp: Option<ast::Expr> = {
961961
}
962962

963963
Atom: ast::Expr = {
964-
<location:@L> <s:(@L string)+> =>? {
965-
let values = s.into_iter().map(|(loc, (value, kind))| {
966-
if let StringKind::F = kind {
967-
parse_located_fstring(&value, loc)
968-
} else {
969-
let kind = (kind == StringKind::U).then(|| "u".to_owned());
970-
Ok(ast::Expr::new(
971-
loc,
972-
ast::ExprKind::Constant { value: value.into(), kind },
973-
))
974-
}
975-
});
976-
let values = values.collect::<Result<Vec<_>, _>>()?;
977-
978-
Ok(if values.len() > 1 {
979-
ast::Expr::new(location, ast::ExprKind::JoinedStr { values })
980-
} else {
981-
values.into_iter().next().unwrap()
982-
})
983-
},
964+
<location:@L> <s:(@L string)+> =>? parse_strings(s).map_err(|e| e.into()),
984965
<location:@L> <value:Constant> => ast::Expr {
985966
location,
986967
custom: (),

parser/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,5 @@ pub mod mode;
3030
pub mod parser;
3131
#[rustfmt::skip]
3232
mod python;
33+
mod string;
3334
pub mod token;

parser/src/parser.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,20 @@ mod tests {
9191
insta::assert_debug_snapshot!(parse_ast);
9292
}
9393

94+
#[test]
95+
fn test_parse_string() {
96+
let source = String::from("'Hello world'");
97+
let parse_ast = parse_program(&source).unwrap();
98+
insta::assert_debug_snapshot!(parse_ast);
99+
}
100+
101+
#[test]
102+
fn test_parse_f_string() {
103+
let source = String::from("f'Hello world'");
104+
let parse_ast = parse_program(&source).unwrap();
105+
insta::assert_debug_snapshot!(parse_ast);
106+
}
107+
94108
#[test]
95109
fn test_parse_print_hello() {
96110
let source = String::from("print('Hello world')");
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
---
2+
source: parser/src/parser.rs
3+
expression: parse_ast
4+
---
5+
[
6+
Located {
7+
location: Location {
8+
row: 1,
9+
column: 3,
10+
},
11+
custom: (),
12+
node: Expr {
13+
value: Located {
14+
location: Location {
15+
row: 1,
16+
column: 3,
17+
},
18+
custom: (),
19+
node: JoinedStr {
20+
values: [
21+
Located {
22+
location: Location {
23+
row: 1,
24+
column: 3,
25+
},
26+
custom: (),
27+
node: Constant {
28+
value: Str(
29+
"Hello world",
30+
),
31+
kind: None,
32+
},
33+
},
34+
],
35+
},
36+
},
37+
},
38+
},
39+
]
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
source: parser/src/parser.rs
3+
expression: parse_ast
4+
---
5+
[
6+
Located {
7+
location: Location {
8+
row: 1,
9+
column: 2,
10+
},
11+
custom: (),
12+
node: Expr {
13+
value: Located {
14+
location: Location {
15+
row: 1,
16+
column: 2,
17+
},
18+
custom: (),
19+
node: Constant {
20+
value: Str(
21+
"Hello world",
22+
),
23+
kind: None,
24+
},
25+
},
26+
},
27+
},
28+
]
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
---
2+
source: parser/src/string.rs
3+
expression: parse_ast
4+
---
5+
[
6+
Located {
7+
location: Location {
8+
row: 1,
9+
column: 2,
10+
},
11+
custom: (),
12+
node: Expr {
13+
value: Located {
14+
location: Location {
15+
row: 1,
16+
column: 2,
17+
},
18+
custom: (),
19+
node: JoinedStr {
20+
values: [
21+
Located {
22+
location: Location {
23+
row: 1,
24+
column: 2,
25+
},
26+
custom: (),
27+
node: Constant {
28+
value: Str(
29+
"Hello world",
30+
),
31+
kind: None,
32+
},
33+
},
34+
],
35+
},
36+
},
37+
},
38+
},
39+
]
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
---
2+
source: parser/src/string.rs
3+
expression: parse_ast
4+
---
5+
[
6+
Located {
7+
location: Location {
8+
row: 1,
9+
column: 2,
10+
},
11+
custom: (),
12+
node: Expr {
13+
value: Located {
14+
location: Location {
15+
row: 1,
16+
column: 2,
17+
},
18+
custom: (),
19+
node: JoinedStr {
20+
values: [
21+
Located {
22+
location: Location {
23+
row: 1,
24+
column: 2,
25+
},
26+
custom: (),
27+
node: Constant {
28+
value: Str(
29+
"Hello world",
30+
),
31+
kind: None,
32+
},
33+
},
34+
],
35+
},
36+
},
37+
},
38+
},
39+
]
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
---
2+
source: parser/src/string.rs
3+
expression: parse_ast
4+
---
5+
[
6+
Located {
7+
location: Location {
8+
row: 1,
9+
column: 2,
10+
},
11+
custom: (),
12+
node: Expr {
13+
value: Located {
14+
location: Location {
15+
row: 1,
16+
column: 2,
17+
},
18+
custom: (),
19+
node: JoinedStr {
20+
values: [
21+
Located {
22+
location: Location {
23+
row: 1,
24+
column: 2,
25+
},
26+
custom: (),
27+
node: Constant {
28+
value: Str(
29+
"Hello world",
30+
),
31+
kind: None,
32+
},
33+
},
34+
Located {
35+
location: Location {
36+
row: 1,
37+
column: 12,
38+
},
39+
custom: (),
40+
node: FormattedValue {
41+
value: Located {
42+
location: Location {
43+
row: 1,
44+
column: 3,
45+
},
46+
custom: (),
47+
node: Constant {
48+
value: Str(
49+
"!",
50+
),
51+
kind: None,
52+
},
53+
},
54+
conversion: 0,
55+
format_spec: None,
56+
},
57+
},
58+
],
59+
},
60+
},
61+
},
62+
},
63+
]
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
source: parser/src/string.rs
3+
expression: parse_ast
4+
---
5+
[
6+
Located {
7+
location: Location {
8+
row: 1,
9+
column: 2,
10+
},
11+
custom: (),
12+
node: Expr {
13+
value: Located {
14+
location: Location {
15+
row: 1,
16+
column: 2,
17+
},
18+
custom: (),
19+
node: Constant {
20+
value: Str(
21+
"Hello world",
22+
),
23+
kind: None,
24+
},
25+
},
26+
},
27+
},
28+
]
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
---
2+
source: parser/src/string.rs
3+
expression: parse_ast
4+
---
5+
[
6+
Located {
7+
location: Location {
8+
row: 1,
9+
column: 3,
10+
},
11+
custom: (),
12+
node: Expr {
13+
value: Located {
14+
location: Location {
15+
row: 1,
16+
column: 3,
17+
},
18+
custom: (),
19+
node: JoinedStr {
20+
values: [
21+
Located {
22+
location: Location {
23+
row: 1,
24+
column: 3,
25+
},
26+
custom: (),
27+
node: Constant {
28+
value: Str(
29+
"Hello world",
30+
),
31+
kind: Some(
32+
"u",
33+
),
34+
},
35+
},
36+
],
37+
},
38+
},
39+
},
40+
},
41+
]

0 commit comments

Comments
 (0)