More advanced class semantics

This commit is contained in:
2026-06-16 15:54:21 +02:00
parent ecfff0ac0d
commit d434ec78e7
2 changed files with 152 additions and 28 deletions
+141 -23
View File
@@ -1,6 +1,6 @@
use crate::ast::{
Block, ClassItem, Expression, FunctionDecl, Identifier, Postfix, Spanned, TopLevel,
TopLevelKind,
Block, ClassItem, Expression, FunctionDecl, Identifier, MatchItem, Postfix, Prefix, Spanned,
Statement, StatementBranch, TopLevel, TopLevelKind, VarDeclStmt,
};
pub trait GetMutability {
@@ -112,28 +112,123 @@ impl GetMutability for Block {
}
}
impl GetMutability for Statement {
fn get_mutability(&self) -> Vec<Identifier> {
match self {
Statement::Block(body) | Statement::UnsafeBlock(body) => body.get_mutability(),
Statement::If {
initial,
else_if,
else_branch,
} => {
let mut all_sets: Vec<Vec<Identifier>> = Vec::new();
all_sets.push(initial.body.get_mutability());
for branch in else_if {
all_sets.push(branch.body.get_mutability());
}
if let Some(else_block) = else_branch {
all_sets.push(else_block.get_mutability());
} else {
return Vec::new();
}
let mut result = all_sets.remove(0);
for set in all_sets {
result.retain(|id| set.contains(id));
}
result
}
Statement::Loop(body) => body.get_mutability(),
Statement::While(branch) => branch.body.get_mutability(),
Statement::CStyleFor {
body, init, condition, update, ..
} => {
let mut a = init.get_mutability();
a.append(&mut condition.get_mutability());
a.append(&mut update.get_mutability());
a.append(&mut body.get_mutability());
a
}
Statement::For { body, iterator, .. } => {
let mut a = iterator.get_mutability();
a.append(&mut body.get_mutability());
a
}
Statement::Match(_, items) => {
if items.is_empty() {
return Vec::new();
}
let mut all_sets: Vec<Vec<Identifier>> =
items.iter().map(|item| item.item.get_mutability()).collect();
let mut result = all_sets.remove(0);
for set in all_sets {
result.retain(|id| set.contains(id));
}
result
}
Statement::VarDecl(stmt) => stmt
.init
.as_ref()
.map(|e| e.get_mutability())
.unwrap_or_default(),
Statement::Return(expr) => expr
.as_ref()
.map(|e| e.get_mutability())
.unwrap_or_default(),
Statement::Break | Statement::Continue => Vec::new(),
}
}
}
impl GetMutability for StatementBranch {
fn get_mutability(&self) -> Vec<Identifier> {
let mut a = self.condition.get_mutability();
a.append(&mut self.body.get_mutability());
a
}
}
impl GetMutability for MatchItem {
fn get_mutability(&self) -> Vec<Identifier> {
self.1.get_mutability()
}
}
impl GetMutability for VarDeclStmt {
fn get_mutability(&self) -> Vec<Identifier> {
self.init
.as_ref()
.map(|e| e.get_mutability())
.unwrap_or_default()
}
}
fn get_self_ref(initial: &Expression, postfixes: &[Postfix]) -> Option<Identifier> {
match initial {
Expression::Path(v) => {
if v.0.first()?.ident.0 == "self" {
if let Some(Postfix::FieldAccess(field, _)) = postfixes.first() {
if !matches!(postfixes.get(1), Some(Postfix::Call(_))) {
return Some(field.clone());
}
}
}
}
_ => {}
}
None
}
impl Expression {
fn get_self_ref(&self) -> Option<Identifier> {
match self {
Self::Fix {
initial, postfixes, ..
} => match &**initial {
Self::Path(v) => {
if v.0[0].ident.0 == "self" {
if let Some(field) = postfixes.get(0) {
match field {
Postfix::FieldAccess(field, _) => return Some(field.clone()),
_ => {}
}
}
}
}
_ => {}
},
_ => {}
} => get_self_ref(initial, postfixes),
_ => None,
}
None
}
}
@@ -162,14 +257,37 @@ impl GetMutability for Expression {
a
}
}
_ => Vec::new(),
Self::Statement(stmt) => stmt.get_mutability(),
Self::Fix {
initial,
prefixes,
postfixes,
} => {
let mut result = Vec::new();
if prefixes.iter().any(|p| matches!(p, Prefix::RefMut)) {
if let Some(self_ref) = get_self_ref(initial, postfixes) {
result.push(self_ref);
}
}
for postfix in postfixes {
if let Postfix::Assign(_, rhs) = postfix {
if let Some(self_ref) = get_self_ref(initial, postfixes) {
result.push(self_ref);
}
result.append(&mut rhs.get_mutability());
}
}
result
}
Self::Closure { body, .. } => body.get_mutability(),
Self::Literal(_) | Self::Path(_) => Vec::new(),
}
}
}
pub fn mutates_lhs(op: &str) -> bool {
matches!(
op,
"=" | "+=" | "-=" | "*=" | "/=" | "%=" | "&=" | "|=" | "^=" | "<<=" | ">>=" | "->"
)
matches!(op, "=" | "->" | "+=" | "-=" | "*=" | "/=")
}