diff --git a/src/compile.rs b/src/compile.rs index efb5e08..6e5cbfc 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -680,6 +680,7 @@ impl Compiler { orelse, .. } => self.compile_for(target, iter, body, orelse, true)?, + Match { subject, cases } => self.compile_match(subject, cases)?, Raise { exc, cause } => { let kind = match exc { Some(value) => { @@ -881,17 +882,19 @@ impl Compiler { }); } - let mut num_kw_only_defaults = 0; - for (kw, default) in args.kwonlyargs.iter().zip(&args.kw_defaults) { - self.emit_constant(ConstantData::Str { - value: kw.node.arg.clone(), - }); - self.compile_expression(default)?; - num_kw_only_defaults += 1; - } - if num_kw_only_defaults > 0 { + if !args.kw_defaults.is_empty() { + let required_kw_count = args.kwonlyargs.len().saturating_sub(args.kw_defaults.len()); + for (kw, default) in args.kwonlyargs[required_kw_count..] + .iter() + .zip(&args.kw_defaults) + { + self.emit_constant(ConstantData::Str { + value: kw.node.arg.clone(), + }); + self.compile_expression(default)?; + } self.emit(Instruction::BuildMap { - size: num_kw_only_defaults, + size: args.kw_defaults.len() as u32, unpack: false, for_call: false, }); @@ -901,7 +904,7 @@ impl Compiler { if have_defaults { funcflags |= bytecode::MakeFunctionFlags::DEFAULTS; } - if num_kw_only_defaults > 0 { + if !args.kw_defaults.is_empty() { funcflags |= bytecode::MakeFunctionFlags::KW_ONLY_DEFAULTS; } @@ -1519,6 +1522,16 @@ impl Compiler { Ok(()) } + fn compile_match( + &mut self, + subject: &ast::Expr, + cases: &[ast::MatchCase], + ) -> CompileResult<()> { + eprintln!("match subject: {subject:?}"); + eprintln!("match cases: {cases:?}"); + Err(self.error(CompileErrorType::NotImplementedYet)) + } + fn compile_chained_comparison( &mut self, left: &ast::Expr, @@ -1928,11 +1941,7 @@ impl Compiler { Ok(()) } - fn compile_dict( - &mut self, - keys: &[ast::Expr], - values: &[ast::Expr], - ) -> CompileResult<()> { + fn compile_dict(&mut self, keys: &[ast::Expr], values: &[ast::Expr]) -> CompileResult<()> { let mut size = 0; let (packed_values, unpacked_values) = values.split_at(keys.len()); @@ -2099,7 +2108,7 @@ impl Compiler { }; self.compile_expression(value)?; self.emit(Instruction::FormatValue { - conversion: compile_conversion_flag(*conversion), + conversion: (*conversion).try_into().expect("invalid conversion flag"), }); } Name { id, .. } => self.load_name(id)?, @@ -2454,7 +2463,7 @@ impl Compiler { let mut loop_labels = vec![]; for generator in generators { - if generator.is_async { + if generator.is_async > 0 { unimplemented!("async for comprehensions"); } @@ -2543,7 +2552,7 @@ impl Compiler { return Err(self.error(CompileErrorType::InvalidFuturePlacement)); } for feature in features { - match &*feature.name { + match &*feature.node.name { // Python 3 features; we've already implemented them by default "nested_scopes" | "generators" | "division" | "absolute_import" | "with_statement" | "print_function" | "unicode_literals" => {} @@ -2667,17 +2676,6 @@ fn compile_location(location: &ast::Location) -> bytecode::Location { bytecode::Location::new(location.row(), location.column()) } -fn compile_conversion_flag( - conversion_flag: Option, -) -> bytecode::ConversionFlag { - match conversion_flag { - None => bytecode::ConversionFlag::None, - Some(ast::ConversionFlag::Ascii) => bytecode::ConversionFlag::Ascii, - Some(ast::ConversionFlag::Repr) => bytecode::ConversionFlag::Repr, - Some(ast::ConversionFlag::Str) => bytecode::ConversionFlag::Str, - } -} - fn compile_constant(value: &ast::Constant) -> ConstantData { match value { ast::Constant::None => ConstantData::None, diff --git a/src/error.rs b/src/error.rs index 1d2c1c2..2e125b0 100644 --- a/src/error.rs +++ b/src/error.rs @@ -37,6 +37,7 @@ pub enum CompileErrorType { TooManyStarUnpack, EmptyWithItems, EmptyWithBody, + NotImplementedYet, // RustPython marker for unimplemented features } impl fmt::Display for CompileErrorType { @@ -78,6 +79,9 @@ impl fmt::Display for CompileErrorType { CompileErrorType::EmptyWithBody => { write!(f, "empty body on With") } + CompileErrorType::NotImplementedYet => { + write!(f, "RustPython does not implement this feature yet") + } } } } diff --git a/src/symboltable.rs b/src/symboltable.rs index 3876563..6dad4f2 100644 --- a/src/symboltable.rs +++ b/src/symboltable.rs @@ -639,7 +639,7 @@ impl SymbolTableBuilder { if let ImportFrom { module, names, .. } = &statement.node { if module.as_deref() == Some("__future__") { for feature in names { - if feature.name == "annotations" { + if feature.node.name == "annotations" { self.future_annotations = true; } } @@ -739,13 +739,13 @@ impl SymbolTableBuilder { } Import { names } | ImportFrom { names, .. } => { for name in names { - if let Some(alias) = &name.asname { + if let Some(alias) = &name.node.asname { // `import mymodule as myalias` self.register_name(alias, SymbolUsage::Imported, location)?; } else { // `import module` self.register_name( - name.name.split('.').next().unwrap(), + name.node.name.split('.').next().unwrap(), SymbolUsage::Imported, location, )?; @@ -782,7 +782,7 @@ impl SymbolTableBuilder { } => { // https://github.com/python/cpython/blob/main/Python/symtable.c#L1233 match &target.node { - ast::ExprKind::Name { id, .. } if *simple => { + ast::ExprKind::Name { id, .. } if *simple > 0 => { self.register_name(id, SymbolUsage::AnnotationAssigned, location)?; } _ => { @@ -823,6 +823,15 @@ impl SymbolTableBuilder { self.scan_statements(orelse)?; self.scan_statements(finalbody)?; } + Match { + subject: _, + cases: _, + } => { + return Err(SymbolTableError { + error: "match expression is not implemented yet".to_owned(), + location: Location::default(), + }); + } Raise { exc, cause } => { if let Some(expression) = exc { self.scan_expression(expression, ExpressionContext::Load)?; @@ -875,12 +884,13 @@ impl SymbolTableBuilder { self.scan_expression(value, ExpressionContext::Load)?; } Dict { keys, values } => { - for (key, value) in keys.iter().zip(values) { - if let Some(key) = key { - self.scan_expression(key, context)?; - } else { - // dict unpacking marker - } + let (packed, unpacked) = values.split_at(keys.len()); + for (key, value) in keys.iter().zip(packed) { + self.scan_expression(key, context)?; + self.scan_expression(value, context)?; + } + for value in unpacked { + // dict unpacking marker self.scan_expression(value, context)?; } }