Skip to content

Commit 53b3448

Browse files
committed
Implement new features for updated python asdl
1 parent 0d334a9 commit 53b3448

29 files changed

+182
-156
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.

ast/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ unparse = ["rustpython-common"]
1313
[dependencies]
1414
num-bigint = "0.4.3"
1515
rustpython-common = { path = "../common", optional = true }
16+
rustpython-bytecode = { path = "../bytecode"}

ast/src/constant.rs

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use num_bigint::BigInt;
2+
pub use rustpython_bytecode::ConversionFlag;
23

34
#[derive(Debug, PartialEq)]
45
pub enum Constant {
@@ -70,35 +71,6 @@ impl std::fmt::Display for Constant {
7071
}
7172
}
7273

73-
/// Transforms a value prior to formatting it.
74-
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
75-
#[repr(usize)]
76-
pub enum ConversionFlag {
77-
/// Converts by calling `str(<value>)`.
78-
Str = b's' as usize,
79-
/// Converts by calling `ascii(<value>)`.
80-
Ascii = b'a' as usize,
81-
/// Converts by calling `repr(<value>)`.
82-
Repr = b'r' as usize,
83-
}
84-
85-
impl ConversionFlag {
86-
pub fn try_from_u32(b: usize) -> Option<Self> {
87-
match b.try_into().ok()? {
88-
b's' => Some(Self::Str),
89-
b'a' => Some(Self::Ascii),
90-
b'r' => Some(Self::Repr),
91-
_ => None,
92-
}
93-
}
94-
}
95-
96-
impl From<usize> for ConversionFlag {
97-
fn from(b: usize) -> Self {
98-
Self::try_from_u32(b).unwrap()
99-
}
100-
}
101-
10274
#[cfg(feature = "constant-optimization")]
10375
#[non_exhaustive]
10476
#[derive(Default)]

ast/src/fold_helpers.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,4 @@ macro_rules! simple_fold {
6363
};
6464
}
6565

66-
simple_fold!(
67-
usize,
68-
String,
69-
bool,
70-
constant::Constant,
71-
constant::ConversionFlag
72-
);
66+
simple_fold!(usize, String, bool, constant::Constant);

ast/src/unparse.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ impl<'a> Unparser<'a> {
155155
write!(self, "{}: {}", *k, *v)?;
156156
}
157157
for d in unpacked {
158+
self.p_delim(&mut first, ", ")?;
158159
write!(self, "**{}", *d)?;
159160
}
160161
self.p("}")?;
@@ -281,7 +282,7 @@ impl<'a> Unparser<'a> {
281282
value,
282283
conversion,
283284
format_spec,
284-
} => self.unparse_formatted(value, (*conversion).into(), format_spec.as_deref())?,
285+
} => self.unparse_formatted(value, *conversion, format_spec.as_deref())?,
285286
ExprKind::JoinedStr { values } => self.unparse_joinedstr(values, false)?,
286287
ExprKind::Constant { value, kind } => {
287288
if let Some(kind) = kind {
@@ -445,7 +446,7 @@ impl<'a> Unparser<'a> {
445446
fn unparse_formatted<U>(
446447
&mut self,
447448
val: &Expr<U>,
448-
conversion: ConversionFlag,
449+
conversion: usize,
449450
spec: Option<&Expr<U>>,
450451
) -> fmt::Result {
451452
let buffered = to_string_fmt(|f| Unparser::new(f).unparse_expr(val, precedence::TEST + 1));
@@ -459,12 +460,12 @@ impl<'a> Unparser<'a> {
459460
self.p(&buffered)?;
460461
drop(buffered);
461462

462-
let flag = match conversion {
463-
ConversionFlag::Str => "!s",
464-
ConversionFlag::Ascii => "!a",
465-
ConversionFlag::Repr => "!r",
466-
};
467-
self.p(flag)?;
463+
if conversion != ConversionFlag::None as usize {
464+
self.p("!")?;
465+
let buf = &[conversion as u8];
466+
let c = std::str::from_utf8(buf).unwrap();
467+
self.p(c)?;
468+
}
468469

469470
if let Some(spec) = spec {
470471
self.p(":")?;
@@ -490,7 +491,7 @@ impl<'a> Unparser<'a> {
490491
value,
491492
conversion,
492493
format_spec,
493-
} => self.unparse_formatted(value, (*conversion).into(), format_spec.as_deref()),
494+
} => self.unparse_formatted(value, *conversion, format_spec.as_deref()),
494495
_ => unreachable!(),
495496
}
496497
}

bytecode/src/lib.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,15 +159,30 @@ impl fmt::Display for Label {
159159

160160
/// Transforms a value prior to formatting it.
161161
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
162+
#[repr(u8)]
162163
pub enum ConversionFlag {
163164
/// No conversion
164-
None,
165+
None = 0,
165166
/// Converts by calling `str(<value>)`.
166-
Str,
167+
Str = b's',
167168
/// Converts by calling `ascii(<value>)`.
168-
Ascii,
169+
Ascii = b'a',
169170
/// Converts by calling `repr(<value>)`.
170-
Repr,
171+
Repr = b'r',
172+
}
173+
174+
impl TryFrom<usize> for ConversionFlag {
175+
type Error = usize;
176+
fn try_from(b: usize) -> Result<Self, Self::Error> {
177+
let b = b.try_into().map_err(|_| b)?;
178+
match b {
179+
0 => Ok(Self::None),
180+
b's' => Ok(Self::Str),
181+
b'a' => Ok(Self::Ascii),
182+
b'r' => Ok(Self::Repr),
183+
b => Err(b as usize),
184+
}
185+
}
171186
}
172187

173188
/// The kind of Raise that occurred.

compiler/src/compile.rs

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,7 @@ impl Compiler {
680680
orelse,
681681
..
682682
} => self.compile_for(target, iter, body, orelse, true)?,
683+
Match { subject, cases } => self.compile_match(subject, cases)?,
683684
Raise { exc, cause } => {
684685
let kind = match exc {
685686
Some(value) => {
@@ -881,17 +882,19 @@ impl Compiler {
881882
});
882883
}
883884

884-
let mut num_kw_only_defaults = 0;
885-
for (kw, default) in args.kwonlyargs.iter().zip(&args.kw_defaults) {
886-
self.emit_constant(ConstantData::Str {
887-
value: kw.node.arg.clone(),
888-
});
889-
self.compile_expression(default)?;
890-
num_kw_only_defaults += 1;
891-
}
892-
if num_kw_only_defaults > 0 {
885+
if !args.kw_defaults.is_empty() {
886+
let required_kw_count = args.kwonlyargs.len().saturating_sub(args.kw_defaults.len());
887+
for (kw, default) in args.kwonlyargs[required_kw_count..]
888+
.iter()
889+
.zip(&args.kw_defaults)
890+
{
891+
self.emit_constant(ConstantData::Str {
892+
value: kw.node.arg.clone(),
893+
});
894+
self.compile_expression(default)?;
895+
}
893896
self.emit(Instruction::BuildMap {
894-
size: num_kw_only_defaults,
897+
size: args.kw_defaults.len() as u32,
895898
unpack: false,
896899
for_call: false,
897900
});
@@ -901,7 +904,7 @@ impl Compiler {
901904
if have_defaults {
902905
funcflags |= bytecode::MakeFunctionFlags::DEFAULTS;
903906
}
904-
if num_kw_only_defaults > 0 {
907+
if !args.kw_defaults.is_empty() {
905908
funcflags |= bytecode::MakeFunctionFlags::KW_ONLY_DEFAULTS;
906909
}
907910

@@ -1519,6 +1522,16 @@ impl Compiler {
15191522
Ok(())
15201523
}
15211524

1525+
fn compile_match(
1526+
&mut self,
1527+
subject: &ast::Expr,
1528+
cases: &[ast::MatchCase],
1529+
) -> CompileResult<()> {
1530+
eprintln!("match subject: {subject:?}");
1531+
eprintln!("match cases: {cases:?}");
1532+
Err(self.error(CompileErrorType::NotImplementedYet))
1533+
}
1534+
15221535
fn compile_chained_comparison(
15231536
&mut self,
15241537
left: &ast::Expr,
@@ -1928,11 +1941,7 @@ impl Compiler {
19281941
Ok(())
19291942
}
19301943

1931-
fn compile_dict(
1932-
&mut self,
1933-
keys: &[ast::Expr],
1934-
values: &[ast::Expr],
1935-
) -> CompileResult<()> {
1944+
fn compile_dict(&mut self, keys: &[ast::Expr], values: &[ast::Expr]) -> CompileResult<()> {
19361945
let mut size = 0;
19371946

19381947
let (packed_values, unpacked_values) = values.split_at(keys.len());
@@ -2099,7 +2108,7 @@ impl Compiler {
20992108
};
21002109
self.compile_expression(value)?;
21012110
self.emit(Instruction::FormatValue {
2102-
conversion: compile_conversion_flag(*conversion),
2111+
conversion: (*conversion).try_into().expect("invalid conversion flag"),
21032112
});
21042113
}
21052114
Name { id, .. } => self.load_name(id)?,
@@ -2454,7 +2463,7 @@ impl Compiler {
24542463

24552464
let mut loop_labels = vec![];
24562465
for generator in generators {
2457-
if generator.is_async {
2466+
if generator.is_async > 0 {
24582467
unimplemented!("async for comprehensions");
24592468
}
24602469

@@ -2543,7 +2552,7 @@ impl Compiler {
25432552
return Err(self.error(CompileErrorType::InvalidFuturePlacement));
25442553
}
25452554
for feature in features {
2546-
match &*feature.name {
2555+
match &*feature.node.name {
25472556
// Python 3 features; we've already implemented them by default
25482557
"nested_scopes" | "generators" | "division" | "absolute_import"
25492558
| "with_statement" | "print_function" | "unicode_literals" => {}
@@ -2667,17 +2676,6 @@ fn compile_location(location: &ast::Location) -> bytecode::Location {
26672676
bytecode::Location::new(location.row(), location.column())
26682677
}
26692678

2670-
fn compile_conversion_flag(
2671-
conversion_flag: Option<ast::ConversionFlag>,
2672-
) -> bytecode::ConversionFlag {
2673-
match conversion_flag {
2674-
None => bytecode::ConversionFlag::None,
2675-
Some(ast::ConversionFlag::Ascii) => bytecode::ConversionFlag::Ascii,
2676-
Some(ast::ConversionFlag::Repr) => bytecode::ConversionFlag::Repr,
2677-
Some(ast::ConversionFlag::Str) => bytecode::ConversionFlag::Str,
2678-
}
2679-
}
2680-
26812679
fn compile_constant(value: &ast::Constant) -> ConstantData {
26822680
match value {
26832681
ast::Constant::None => ConstantData::None,

compiler/src/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ pub enum CompileErrorType {
3737
TooManyStarUnpack,
3838
EmptyWithItems,
3939
EmptyWithBody,
40+
NotImplementedYet, // RustPython marker for unimplemented features
4041
}
4142

4243
impl fmt::Display for CompileErrorType {
@@ -78,6 +79,9 @@ impl fmt::Display for CompileErrorType {
7879
CompileErrorType::EmptyWithBody => {
7980
write!(f, "empty body on With")
8081
}
82+
CompileErrorType::NotImplementedYet => {
83+
write!(f, "RustPython does not implement this feature yet")
84+
}
8185
}
8286
}
8387
}

compiler/src/symboltable.rs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -639,7 +639,7 @@ impl SymbolTableBuilder {
639639
if let ImportFrom { module, names, .. } = &statement.node {
640640
if module.as_deref() == Some("__future__") {
641641
for feature in names {
642-
if feature.name == "annotations" {
642+
if feature.node.name == "annotations" {
643643
self.future_annotations = true;
644644
}
645645
}
@@ -739,13 +739,13 @@ impl SymbolTableBuilder {
739739
}
740740
Import { names } | ImportFrom { names, .. } => {
741741
for name in names {
742-
if let Some(alias) = &name.asname {
742+
if let Some(alias) = &name.node.asname {
743743
// `import mymodule as myalias`
744744
self.register_name(alias, SymbolUsage::Imported, location)?;
745745
} else {
746746
// `import module`
747747
self.register_name(
748-
name.name.split('.').next().unwrap(),
748+
name.node.name.split('.').next().unwrap(),
749749
SymbolUsage::Imported,
750750
location,
751751
)?;
@@ -782,7 +782,7 @@ impl SymbolTableBuilder {
782782
} => {
783783
// https://github.com/python/cpython/blob/main/Python/symtable.c#L1233
784784
match &target.node {
785-
ast::ExprKind::Name { id, .. } if *simple => {
785+
ast::ExprKind::Name { id, .. } if *simple > 0 => {
786786
self.register_name(id, SymbolUsage::AnnotationAssigned, location)?;
787787
}
788788
_ => {
@@ -823,6 +823,15 @@ impl SymbolTableBuilder {
823823
self.scan_statements(orelse)?;
824824
self.scan_statements(finalbody)?;
825825
}
826+
Match {
827+
subject: _,
828+
cases: _,
829+
} => {
830+
return Err(SymbolTableError {
831+
error: "match expression is not implemented yet".to_owned(),
832+
location: Location::default(),
833+
});
834+
}
826835
Raise { exc, cause } => {
827836
if let Some(expression) = exc {
828837
self.scan_expression(expression, ExpressionContext::Load)?;
@@ -875,12 +884,13 @@ impl SymbolTableBuilder {
875884
self.scan_expression(value, ExpressionContext::Load)?;
876885
}
877886
Dict { keys, values } => {
878-
for (key, value) in keys.iter().zip(values) {
879-
if let Some(key) = key {
880-
self.scan_expression(key, context)?;
881-
} else {
882-
// dict unpacking marker
883-
}
887+
let (packed, unpacked) = values.split_at(keys.len());
888+
for (key, value) in keys.iter().zip(packed) {
889+
self.scan_expression(key, context)?;
890+
self.scan_expression(value, context)?;
891+
}
892+
for value in unpacked {
893+
// dict unpacking marker
884894
self.scan_expression(value, context)?;
885895
}
886896
}

extra_tests/snippets/builtin_dict.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ class MyClass: pass
285285
z = {'c': 3, 'd': 3, 'e': 3}
286286

287287
w = {1: 1, **x, 2: 2, **y, 3: 3, **z, 4: 4}
288-
assert w == {1: 1, 'a': 1, 'b': 2, 'c': 3, 2: 2, 'd': 3, 3: 3, 'e': 3, 4: 4}
288+
assert w == {1: 1, 'a': 1, 'b': 2, 'c': 3, 2: 2, 'd': 3, 3: 3, 'e': 3, 4: 4} # not in cpython test suite
289289

290290
assert str({True: True, 1.0: 1.0}) == str({True: 1.0})
291291

0 commit comments

Comments
 (0)