Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Match statements #5485

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
Jan 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
9fbd359
initial stub implementation of match statements
arihant2math Jan 19, 2025
bfb4091
formatting
arihant2math Jan 19, 2025
c021326
solved compilation errors
arihant2math Jan 20, 2025
6c7a543
almost working
arihant2math Jan 20, 2025
8617786
formatting
arihant2math Jan 20, 2025
a01240f
as and * support for switch case
arihant2math Jan 20, 2025
d8c4cff
replace todos with errors
arihant2math Jan 20, 2025
aaccadb
fix compile
arihant2math Jan 20, 2025
f9d2418
added Noop instruction
arihant2math Jan 20, 2025
5839dfd
finished default for switch case
arihant2math Jan 20, 2025
40e380e
fix compile
arihant2math Jan 20, 2025
8af2c42
formatting
arihant2math Jan 20, 2025
0774cbd
more implementation
arihant2math Jan 20, 2025
cd0f1cf
rename codegen_* to compile_*
arihant2math Jan 21, 2025
223fbe4
implement SWAP instruction
arihant2math Jan 21, 2025
4ef2a50
applied fix
youknowone Jan 21, 2025
aa6a040
enabled IR debug and attempted to fix codegen
arihant2math Jan 22, 2025
822d565
formatting
arihant2math Jan 22, 2025
ad164c0
basic match statement working
arihant2math Jan 22, 2025
e955ede
basic match statement working
arihant2math Jan 22, 2025
4649898
working as pattern (default works too by extension)
arihant2math Jan 23, 2025
493fc6e
fix rust tests
arihant2math Jan 23, 2025
fe7f8a3
cleanup
arihant2math Jan 23, 2025
805757a
fix clippy errors
arihant2math Jan 23, 2025
b176f9c
formatting
arihant2math Jan 23, 2025
8e78c6d
trivial edits
youknowone Jan 25, 2025
4beef2c
Remove currently unused Nop,Swap op
youknowone Jan 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 151 additions & 4 deletions compiler/codegen/src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ use num_complex::Complex64;
use num_traits::ToPrimitive;
use rustpython_ast::located::{self as located_ast, Located};
use rustpython_compiler_core::{
bytecode::{self, Arg as OpArgMarker, CodeObject, ConstantData, Instruction, OpArg, OpArgType},
bytecode::{
self, Arg as OpArgMarker, CodeObject, ComparisonOperator, ConstantData, Instruction, OpArg,
OpArgType,
},
Mode,
};
use rustpython_parser_core::source_code::{LineNumber, SourceLocation};
Expand Down Expand Up @@ -211,6 +214,12 @@ macro_rules! emit {
};
}

struct PatternContext {
current_block: usize,
blocks: Vec<ir::BlockIdx>,
allow_irrefutable: bool,
}

impl Compiler {
fn new(opts: CompileOpts, source_path: String, code_name: String) -> Self {
let module_code = ir::CodeInfo {
Expand Down Expand Up @@ -1755,14 +1764,152 @@ impl Compiler {
Ok(())
}

fn compile_pattern_value(
&mut self,
value: &located_ast::PatternMatchValue,
_pattern_context: &mut PatternContext,
) -> CompileResult<()> {
self.compile_expression(&value.value)?;
emit!(
self,
Instruction::CompareOperation {
op: ComparisonOperator::Equal
}
);
Ok(())
}

fn compile_pattern_as(
&mut self,
as_pattern: &located_ast::PatternMatchAs,
pattern_context: &mut PatternContext,
) -> CompileResult<()> {
if as_pattern.pattern.is_none() && !pattern_context.allow_irrefutable {
// TODO: better error message
if let Some(_name) = as_pattern.name.as_ref() {
return Err(
self.error_loc(CodegenErrorType::InvalidMatchCase, as_pattern.location())
);
}
return Err(self.error_loc(CodegenErrorType::InvalidMatchCase, as_pattern.location()));
}
// Need to make a copy for (possibly) storing later:
emit!(self, Instruction::Duplicate);
if let Some(pattern) = &as_pattern.pattern {
self.compile_pattern_inner(pattern, pattern_context)?;
}
if let Some(name) = as_pattern.name.as_ref() {
self.store_name(name.as_str())?;
} else {
emit!(self, Instruction::Pop);
}
Ok(())
}

fn compile_pattern_inner(
&mut self,
pattern_type: &located_ast::Pattern,
pattern_context: &mut PatternContext,
) -> CompileResult<()> {
match &pattern_type {
located_ast::Pattern::MatchValue(value) => {
self.compile_pattern_value(value, pattern_context)
}
located_ast::Pattern::MatchAs(as_pattern) => {
self.compile_pattern_as(as_pattern, pattern_context)
}
_ => {
eprintln!("not implemented pattern type: {pattern_type:?}");
Err(self.error(CodegenErrorType::NotImplementedYet))
}
}
}

fn compile_pattern(
&mut self,
pattern_type: &located_ast::Pattern,
pattern_context: &mut PatternContext,
) -> CompileResult<()> {
self.compile_pattern_inner(pattern_type, pattern_context)?;
emit!(
self,
Instruction::JumpIfFalse {
target: pattern_context.blocks[pattern_context.current_block + 1]
}
);
Ok(())
}

fn compile_match_inner(
&mut self,
subject: &located_ast::Expr,
cases: &[located_ast::MatchCase],
pattern_context: &mut PatternContext,
) -> CompileResult<()> {
self.compile_expression(subject)?;
pattern_context.blocks = std::iter::repeat_with(|| self.new_block())
.take(cases.len() + 1)
.collect::<Vec<_>>();
let end_block = *pattern_context.blocks.last().unwrap();

let _match_case_type = cases.last().expect("cases is not empty");
// TODO: get proper check for default case
// let has_default = match_case_type.pattern.is_match_as() && 1 < cases.len();
let has_default = false;
for i in 0..cases.len() - (has_default as usize) {
self.switch_to_block(pattern_context.blocks[i]);
pattern_context.current_block = i;
pattern_context.allow_irrefutable = cases[i].guard.is_some() || i == cases.len() - 1;
let m = &cases[i];
// Only copy the subject if we're *not* on the last case:
if i != cases.len() - has_default as usize - 1 {
emit!(self, Instruction::Duplicate);
}
self.compile_pattern(&m.pattern, pattern_context)?;
self.compile_statements(&m.body)?;
emit!(self, Instruction::Jump { target: end_block });
}
// TODO: below code is not called and does not work
if has_default {
// A trailing "case _" is common, and lets us save a bit of redundant
// pushing and popping in the loop above:
let m = &cases.last().unwrap();
self.switch_to_block(*pattern_context.blocks.last().unwrap());
if cases.len() == 1 {
// No matches. Done with the subject:
emit!(self, Instruction::Pop);
} else {
// Show line coverage for default case (it doesn't create bytecode)
// emit!(self, Instruction::Nop);
}
self.compile_statements(&m.body)?;
}

self.switch_to_block(end_block);

let code = self.current_code_info();
pattern_context
.blocks
.iter()
.zip(pattern_context.blocks.iter().skip(1))
.for_each(|(a, b)| {
code.blocks[a.0 as usize].next = *b;
});
Ok(())
}

fn compile_match(
&mut self,
subject: &located_ast::Expr,
cases: &[located_ast::MatchCase],
) -> CompileResult<()> {
eprintln!("match subject: {subject:?}");
eprintln!("match cases: {cases:?}");
Err(self.error(CodegenErrorType::NotImplementedYet))
let mut pattern_context = PatternContext {
current_block: usize::MAX,
blocks: Vec::new(),
allow_irrefutable: false,
};
self.compile_match_inner(subject, cases, &mut pattern_context)?;
Ok(())
}

fn compile_chained_comparison(
Expand Down
8 changes: 8 additions & 0 deletions compiler/codegen/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ pub enum CodegenErrorType {
TooManyStarUnpack,
EmptyWithItems,
EmptyWithBody,
DuplicateStore(String),
InvalidMatchCase,
NotImplementedYet, // RustPython marker for unimplemented features
}

Expand Down Expand Up @@ -75,6 +77,12 @@ impl fmt::Display for CodegenErrorType {
EmptyWithBody => {
write!(f, "empty body on With")
}
DuplicateStore(s) => {
write!(f, "duplicate store {s}")
}
InvalidMatchCase => {
write!(f, "invalid match case")
}
NotImplementedYet => {
write!(f, "RustPython does not implement this feature yet")
}
Expand Down
12 changes: 7 additions & 5 deletions compiler/codegen/src/symboltable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -886,11 +886,13 @@ impl SymbolTableBuilder {
self.scan_statements(orelse)?;
self.scan_statements(finalbody)?;
}
Stmt::Match(StmtMatch { subject, .. }) => {
return Err(SymbolTableError {
error: "match expression is not implemented yet".to_owned(),
location: Some(subject.location()),
});
Stmt::Match(StmtMatch { subject, cases, .. }) => {
self.scan_expression(subject, ExpressionContext::Load)?;
for case in cases {
// TODO: below
// self.scan_pattern(&case.pattern, ExpressionContext::Load)?;
self.scan_statements(&case.body)?;
}
}
Stmt::Raise(StmtRaise { exc, cause, .. }) => {
if let Some(expression) = exc {
Expand Down
Loading