From d434ec78e76d017e79138b4c6410110e9a5c9855 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 16 Jun 2026 15:54:21 +0200 Subject: [PATCH] More advanced class semantics --- crates/parser/src/semantics.rs | 164 ++++++++++++++++++++++++---- mist-test/src/items/class_test.mist | 16 ++- 2 files changed, 152 insertions(+), 28 deletions(-) diff --git a/crates/parser/src/semantics.rs b/crates/parser/src/semantics.rs index 3cfccbe..ac9f95b 100644 --- a/crates/parser/src/semantics.rs +++ b/crates/parser/src/semantics.rs @@ -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 { + match self { + Statement::Block(body) | Statement::UnsafeBlock(body) => body.get_mutability(), + Statement::If { + initial, + else_if, + else_branch, + } => { + let mut all_sets: Vec> = 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> = + 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 { + let mut a = self.condition.get_mutability(); + a.append(&mut self.body.get_mutability()); + a + } +} + +impl GetMutability for MatchItem { + fn get_mutability(&self) -> Vec { + self.1.get_mutability() + } +} + +impl GetMutability for VarDeclStmt { + fn get_mutability(&self) -> Vec { + self.init + .as_ref() + .map(|e| e.get_mutability()) + .unwrap_or_default() + } +} + +fn get_self_ref(initial: &Expression, postfixes: &[Postfix]) -> Option { + 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 { 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, "=" | "->" | "+=" | "-=" | "*=" | "/=") } diff --git a/mist-test/src/items/class_test.mist b/mist-test/src/items/class_test.mist index a95c15a..65310fa 100644 --- a/mist-test/src/items/class_test.mist +++ b/mist-test/src/items/class_test.mist @@ -1,11 +1,17 @@ pub module class_test; -pub class Animal { +pub class Animal { pub name String; - pub val T; + pub val i32; constructor() { self.name = "Rex".to_string(); + + self.init_v(); + } + + pub fn void init_v(*mut self) { + self.val = 0; } pub fn String speak(*self) { @@ -19,7 +25,7 @@ pub class Animal { pub fn void static_method() {} } -pub class Mammal : Animal { +pub class Mammal : Animal { constructor() { super = Super::new(); } @@ -30,12 +36,12 @@ pub class Mammal : Animal { } } -pub class Dog : Mammal { +pub class Dog : Mammal { constructor() { super = Super::new(); } - pub override(Animal) fn String speak(*self) { + pub override(Animal) fn String speak(*self) { "Woof!".to_string() }