From 1babc779574d1b3393babb2fa68a272bea4afb62 Mon Sep 17 00:00:00 2001 From: Selimaj Dev Date: Thu, 16 Apr 2026 09:11:06 +0200 Subject: [PATCH 1/7] Scope postfix ast walking --- semantic/src/scope.rs | 30 +++++++++++++++++++++++++++++- test/src/main.ms | 12 ++++++++---- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/semantic/src/scope.rs b/semantic/src/scope.rs index 92e8a3d..40bd9ee 100644 --- a/semantic/src/scope.rs +++ b/semantic/src/scope.rs @@ -3,7 +3,7 @@ use std::{ sync::{Arc, Mutex}, }; -use parser::ast::{self, ParamList, Statement}; +use parser::ast::{self, ParamList, Postfix, Statement}; use crate::{ hir::{FunctionRef, TopLevelHirScope, TypeRef, VarRef}, @@ -83,6 +83,30 @@ impl LocalScope { } } + pub fn walk_postfixes( + self: &Arc, + initial: &Box, + postfixes: &Vec, + ) -> Option> { + let mut current_type = self.get_type_from_expr(initial)?; + + dbg!(current_type.clone(), initial, postfixes); + + for postfix in postfixes { + match postfix { + Postfix::FieldAccess(id) => match &*current_type { + TypeRef::Struct(s) => { + current_type = s.fields.get(id)?.var_type.clone(); + } + _ => unimplemented!(), + }, + _ => unimplemented!(), + } + } + + Some(current_type) + } + pub fn get_type_from_expr(self: &Arc, expr: &ast::Expression) -> Option> { match expr { ast::Expression::IntLiteral(_) => { @@ -131,6 +155,10 @@ impl LocalScope { _ => None, }, + ast::Expression::Postfix { initial, postfixes } => { + self.walk_postfixes(initial, postfixes) + } + _ => unimplemented!(), } } diff --git a/test/src/main.ms b/test/src/main.ms index 0af918c..d2f6e1a 100644 --- a/test/src/main.ms +++ b/test/src/main.ms @@ -1,5 +1,9 @@ -function add(a: int, b: int) { - let myVar = 10; +struct Test { + x: int +} - let test = myVar; -} \ No newline at end of file +function add() { + let output = test().x; +} + +function test(): Test { } \ No newline at end of file From d27b607686fcc2efa8f673d0386d3f86d13add1c Mon Sep 17 00:00:00 2001 From: Selimaj Dev Date: Thu, 16 Apr 2026 09:14:18 +0200 Subject: [PATCH 2/7] Fixed variable declaration expression --- parser/src/lib.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 7b1a67a..d30e056 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -167,10 +167,9 @@ impl Statement { let kind_pair = inner.next().unwrap(); // let/const/var let name_pair = inner.next().unwrap(); // identifier - let init = inner.next().map(|expr_pair| { - // expects "=" expr - Expression::from_pair(expr_pair.into_inner().next().unwrap()) - }); + println!("{:#?}", inner); + + let init = inner.next().map(Expression::from_pair); let kind = match kind_pair.as_str() { "let" => VarKind::Let, From 8ed8eed5de5e837e440b68c275bfda8d6560ef40 Mon Sep 17 00:00:00 2001 From: Selimaj Dev Date: Thu, 16 Apr 2026 09:45:10 +0200 Subject: [PATCH 3/7] Refactored HIR --- semantic/src/hir.rs | 110 ++++++++++++++++++++------------------------ 1 file changed, 50 insertions(+), 60 deletions(-) diff --git a/semantic/src/hir.rs b/semantic/src/hir.rs index b373688..40a5235 100644 --- a/semantic/src/hir.rs +++ b/semantic/src/hir.rs @@ -1,13 +1,11 @@ use std::{collections::HashMap, sync::Arc}; -use crate::{ - scope::Reference, - top_level::{FunctionSymbol, StructSymbol, TopLevelSymbolScope, TypeSymbol, VarSymbol}, -}; +use crate::top_level::{FunctionSymbol, StructSymbol, TopLevelSymbolScope, TypeSymbol, VarSymbol}; #[derive(Clone, Debug)] pub enum TypeRef { Struct(StructRef), + Function(FunctionRef), Int, } @@ -35,15 +33,13 @@ pub struct StructRef { #[derive(Debug)] pub struct TopLevelHirScope { - pub types: HashMap>, - pub functions: HashMap>, + pub variables: HashMap>, } impl TopLevelHirScope { pub fn from_tlss(tlss: &TopLevelSymbolScope) -> Self { let mut scope = Self { - types: HashMap::new(), - functions: HashMap::new(), + variables: HashMap::new(), }; for (_, symbol) in &tlss.functions { @@ -57,16 +53,10 @@ impl TopLevelHirScope { scope } - pub fn function_ref( - &mut self, - tlss: &TopLevelSymbolScope, - symbol: &FunctionSymbol, - ) -> Arc { - if let Some(rf) = self.functions.get(&symbol.name) { - rf.clone() - } else { + pub fn function_ref(&mut self, tlss: &TopLevelSymbolScope, symbol: &FunctionSymbol) { + if self.variables.get(&symbol.name).is_none() { if let Some(_) = tlss.functions.get(&symbol.name) { - let rf = Arc::new(FunctionRef { + let rf = FunctionRef { export: symbol.export, name: symbol.name.clone(), params: symbol @@ -78,11 +68,15 @@ impl TopLevelHirScope { .return_type .clone() .map(|rt| self.type_ref(tlss, &rt)), - }); + }; - self.functions.insert(symbol.name.clone(), rf.clone()); - - rf + self.variables.insert( + symbol.name.clone(), + Arc::new(VarRef { + name: symbol.name.clone(), + var_type: Arc::new(TypeRef::Function(rf)), + }), + ); } else { unimplemented!() } @@ -105,7 +99,13 @@ impl TopLevelHirScope { methods: HashMap::new(), })); - self.types.insert(symbol.name.clone(), rf.clone()); + self.variables.insert( + symbol.name.clone(), + Arc::new(VarRef { + name: symbol.name.clone(), + var_type: rf.clone(), + }), + ); rf } @@ -118,41 +118,37 @@ impl TopLevelHirScope { } pub fn type_ref(&mut self, tlss: &TopLevelSymbolScope, symbol: &TypeSymbol) -> Arc { - if let Some(rf) = self.types.get(&symbol.0) { - rf.clone() + if let Some(var_ref) = self.variables.get(&symbol.0) { + var_ref.var_type.clone() } else { if let Some(tlss_rf) = tlss.structs.get(&symbol.0) { - let rf = Arc::new(TypeRef::Struct(StructRef { - export: tlss_rf.export, - name: tlss_rf.name.clone(), - fields: tlss_rf - .fields - .iter() - .map(|(name, v)| { - ( - name.clone(), - Arc::new(VarRef { - name: name.clone(), - var_type: self.type_ref(tlss, &v.var_type), - }), - ) - }) - .collect(), - methods: HashMap::new(), - })); + let struct_ref = self.struct_ref(tlss, tlss_rf); - self.types.insert(symbol.0.clone(), rf.clone()); - - rf + self.variables + .insert( + symbol.0.clone(), + Arc::new(VarRef { + name: symbol.0.clone(), + var_type: struct_ref, + }), + ) + .unwrap() + .var_type + .clone() } else { match symbol.0.as_str() { - "int" => { - let rf = Arc::new(TypeRef::Int); - - self.types.insert(symbol.0.clone(), rf.clone()); - - rf - } + "int" => self + .variables + .insert( + symbol.0.clone(), + Arc::new(VarRef { + name: symbol.0.clone(), + var_type: Arc::new(TypeRef::Int), + }), + ) + .unwrap() + .var_type + .clone(), _ => { unimplemented!("{:?}", symbol) @@ -162,13 +158,7 @@ impl TopLevelHirScope { } } - pub fn get_reference(&self, name: &String) -> Option { - if let Some(r) = self.functions.get(name) { - Some(Reference::Func(r.clone())) - } else if let Some(r) = self.types.get(name) { - Some(Reference::Type(r.clone())) - } else { - None - } + pub fn get_reference(&self, name: &String) -> Option<&Arc> { + self.variables.get(name) } } From 819441bc293b1e5844fff46b36047e3b9eeff8b2 Mon Sep 17 00:00:00 2001 From: Selimaj Dev Date: Thu, 16 Apr 2026 09:59:07 +0200 Subject: [PATCH 4/7] Refactored scoping --- semantic/src/hir.rs | 44 ++++++++++------------ semantic/src/scope.rs | 85 +++++++++++++------------------------------ 2 files changed, 45 insertions(+), 84 deletions(-) diff --git a/semantic/src/hir.rs b/semantic/src/hir.rs index 40a5235..1905531 100644 --- a/semantic/src/hir.rs +++ b/semantic/src/hir.rs @@ -124,31 +124,25 @@ impl TopLevelHirScope { if let Some(tlss_rf) = tlss.structs.get(&symbol.0) { let struct_ref = self.struct_ref(tlss, tlss_rf); - self.variables - .insert( - symbol.0.clone(), - Arc::new(VarRef { - name: symbol.0.clone(), - var_type: struct_ref, - }), - ) - .unwrap() - .var_type - .clone() + let var_ref = Arc::new(VarRef { + name: symbol.0.clone(), + var_type: struct_ref, + }); + self.variables.insert(symbol.0.clone(), var_ref.clone()); + + var_ref.var_type.clone() } else { match symbol.0.as_str() { - "int" => self - .variables - .insert( - symbol.0.clone(), - Arc::new(VarRef { - name: symbol.0.clone(), - var_type: Arc::new(TypeRef::Int), - }), - ) - .unwrap() - .var_type - .clone(), + "int" => { + let var_ref = Arc::new(VarRef { + name: symbol.0.clone(), + var_type: Arc::new(TypeRef::Int), + }); + + self.variables.insert(symbol.0.clone(), var_ref.clone()); + + var_ref.var_type.clone() + } _ => { unimplemented!("{:?}", symbol) @@ -158,7 +152,7 @@ impl TopLevelHirScope { } } - pub fn get_reference(&self, name: &String) -> Option<&Arc> { - self.variables.get(name) + pub fn get_reference(&self, name: &String) -> Option> { + self.variables.get(name).cloned() } } diff --git a/semantic/src/scope.rs b/semantic/src/scope.rs index 40bd9ee..4c48f4c 100644 --- a/semantic/src/scope.rs +++ b/semantic/src/scope.rs @@ -6,17 +6,10 @@ use std::{ use parser::ast::{self, ParamList, Postfix, Statement}; use crate::{ - hir::{FunctionRef, TopLevelHirScope, TypeRef, VarRef}, + hir::{TopLevelHirScope, TypeRef, VarRef}, top_level::TopLevelSymbolScope, }; -#[derive(Clone, Debug)] -pub enum Reference { - Type(Arc), - Var(Arc), - Func(Arc), -} - #[derive(Debug)] pub enum Scope { TopLevel(TopLevelHirScope), @@ -29,7 +22,7 @@ impl Scope { Arc::new(Self::TopLevel(TopLevelHirScope::from_tlss(&tl))) } - pub fn get_reference(&self, name: &String) -> Option { + pub fn get_reference(&self, name: &String) -> Option> { match self { Scope::TopLevel(tl) => tl.get_reference(name), Scope::Local(l) => l.get_reference(name), @@ -51,13 +44,12 @@ impl LocalScope { }) } - pub fn get_reference(&self, name: &String) -> Option { + pub fn get_reference(&self, name: &String) -> Option> { self.variables .lock() .unwrap() .get(name) .cloned() - .map(Reference::Var) .or_else(|| self.parent.get_reference(name)) } @@ -109,75 +101,50 @@ impl LocalScope { pub fn get_type_from_expr(self: &Arc, expr: &ast::Expression) -> Option> { match expr { - ast::Expression::IntLiteral(_) => { - self.parent.get_reference(&"int".to_string()).map(|r| { - if let Reference::Type(tr) = &r { - tr.clone() - } else { - unimplemented!() - } - }) - } + ast::Expression::IntLiteral(_) => self + .parent + .get_reference(&"int".to_string()) + .map(|r| r.var_type.clone()), - ast::Expression::FloatLiteral(_) => { - self.parent.get_reference(&"float".to_string()).map(|r| { - if let Reference::Type(tr) = &r { - tr.clone() - } else { - unimplemented!() - } - }) - } + ast::Expression::FloatLiteral(_) => self + .parent + .get_reference(&"float".to_string()) + .map(|r| r.var_type.clone()), - ast::Expression::BoolLiteral(_) => { - self.parent.get_reference(&"bool".to_string()).map(|r| { - if let Reference::Type(tr) = &r { - tr.clone() - } else { - unimplemented!() - } - }) - } + ast::Expression::BoolLiteral(_) => self + .parent + .get_reference(&"bool".to_string()) + .map(|r| r.var_type.clone()), - ast::Expression::StringLiteral(_) => { - self.parent.get_reference(&"string".to_string()).map(|r| { - if let Reference::Type(tr) = &r { - tr.clone() - } else { - unimplemented!() - } - }) - } + ast::Expression::StringLiteral(_) => self + .parent + .get_reference(&"string".to_string()) + .map(|r| r.var_type.clone()), - ast::Expression::Identifier(id) => match self.get_reference(id) { - Some(Reference::Var(var_ref)) => Some(var_ref.var_type.clone()), - Some(Reference::Func(func_ref)) => func_ref.return_type.clone(), - _ => None, - }, + ast::Expression::Identifier(id) => self.get_reference(id).map(|r| r.var_type.clone()), ast::Expression::Postfix { initial, postfixes } => { self.walk_postfixes(initial, postfixes) } - - _ => unimplemented!(), } } pub fn with_params(self: &Arc, param_list: &ParamList) { for (param_name, type_expr) in ¶m_list.0 { match type_expr { - parser::ast::TypeExpr::Identifier(id) => match self.parent.get_reference(id) { - Some(Reference::Type(type_ref)) => { + parser::ast::TypeExpr::Identifier(id) => { + if let Some(var_type) = + self.parent.get_reference(id).map(|r| r.var_type.clone()) + { self.variables.lock().unwrap().insert( param_name.clone(), Arc::new(VarRef { - var_type: type_ref, + var_type, name: param_name.clone(), }), ); } - _ => unimplemented!(), - }, + } } } } From 3e1fa5cd180848d0d97fa92d3de9a65f553e62b9 Mon Sep 17 00:00:00 2001 From: Selimaj Dev Date: Thu, 16 Apr 2026 10:03:24 +0200 Subject: [PATCH 5/7] Working type checker with functions --- semantic/src/lib.rs | 16 ++-------------- semantic/src/scope.rs | 7 +++++++ test/src/main.ms | 4 ++-- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/semantic/src/lib.rs b/semantic/src/lib.rs index 8dd6f97..3405a2e 100644 --- a/semantic/src/lib.rs +++ b/semantic/src/lib.rs @@ -11,27 +11,15 @@ pub fn walk_ast(top_scope: Arc, tl: &mut Vec) { match tl { parser::ast::TopLevel::Import(_) => unimplemented!(), - parser::ast::TopLevel::FunctionDecl { - export, - name, - params, - return_type, - body, - } => { + parser::ast::TopLevel::FunctionDecl { params, body, .. } => { let scope = LocalScope::new(top_scope.clone()); scope.with_params(params); scope.with_block(body); - - println!("{:?}", scope); } - parser::ast::TopLevel::StructDecl { - export, - name, - fields, - } => {} + parser::ast::TopLevel::StructDecl { .. } => {} } } } diff --git a/semantic/src/scope.rs b/semantic/src/scope.rs index 4c48f4c..a2f4ac6 100644 --- a/semantic/src/scope.rs +++ b/semantic/src/scope.rs @@ -92,6 +92,13 @@ impl LocalScope { } _ => unimplemented!(), }, + Postfix::Call(_args) => match &*current_type { + TypeRef::Function(s) => { + // TODO: arg checking + current_type = s.return_type.clone()?; + } + _ => unimplemented!(), + }, _ => unimplemented!(), } } diff --git a/test/src/main.ms b/test/src/main.ms index d2f6e1a..5b271de 100644 --- a/test/src/main.ms +++ b/test/src/main.ms @@ -3,7 +3,7 @@ struct Test { } function add() { - let output = test().x; + let output = test(); } -function test(): Test { } \ No newline at end of file +function test(): int { } \ No newline at end of file From 2d46afff9adaf27fd53306daa7d45c87823c8d40 Mon Sep 17 00:00:00 2001 From: Selimaj Dev Date: Thu, 16 Apr 2026 10:12:49 +0200 Subject: [PATCH 6/7] Variable indexing --- semantic/src/hir.rs | 14 +++++++++++++- semantic/src/scope.rs | 7 +++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/semantic/src/hir.rs b/semantic/src/hir.rs index 1905531..fee6355 100644 --- a/semantic/src/hir.rs +++ b/semantic/src/hir.rs @@ -1,4 +1,10 @@ -use std::{collections::HashMap, sync::Arc}; +use std::{ + collections::HashMap, + sync::{ + Arc, + atomic::{AtomicUsize, Ordering}, + }, +}; use crate::top_level::{FunctionSymbol, StructSymbol, TopLevelSymbolScope, TypeSymbol, VarSymbol}; @@ -34,12 +40,14 @@ pub struct StructRef { #[derive(Debug)] pub struct TopLevelHirScope { pub variables: HashMap>, + pub var_idx: AtomicUsize, } impl TopLevelHirScope { pub fn from_tlss(tlss: &TopLevelSymbolScope) -> Self { let mut scope = Self { variables: HashMap::new(), + var_idx: AtomicUsize::new(0), }; for (_, symbol) in &tlss.functions { @@ -155,4 +163,8 @@ impl TopLevelHirScope { pub fn get_reference(&self, name: &String) -> Option> { self.variables.get(name).cloned() } + + pub fn next_var_idx(&self) -> usize { + self.var_idx.fetch_add(1, Ordering::Relaxed) + 1 + } } diff --git a/semantic/src/scope.rs b/semantic/src/scope.rs index a2f4ac6..116bb1d 100644 --- a/semantic/src/scope.rs +++ b/semantic/src/scope.rs @@ -28,6 +28,13 @@ impl Scope { Scope::Local(l) => l.get_reference(name), } } + + pub fn next_var_idx(&self) -> usize { + match self { + Scope::TopLevel(tl) => tl.next_var_idx(), + Scope::Local(l) => l.parent.next_var_idx(), + } + } } #[derive(Debug)] From 1edcdade33c25677fbf02c71685944dd16011b73 Mon Sep 17 00:00:00 2001 From: Selimaj Dev Date: Thu, 16 Apr 2026 10:25:47 +0200 Subject: [PATCH 7/7] Incremental naming --- semantic/src/hir.rs | 18 ++++++++++++------ semantic/src/scope.rs | 2 -- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/semantic/src/hir.rs b/semantic/src/hir.rs index fee6355..aa242cf 100644 --- a/semantic/src/hir.rs +++ b/semantic/src/hir.rs @@ -34,7 +34,6 @@ pub struct StructRef { pub export: bool, pub name: String, pub fields: HashMap>, - pub methods: HashMap, } #[derive(Debug)] @@ -63,10 +62,12 @@ impl TopLevelHirScope { pub fn function_ref(&mut self, tlss: &TopLevelSymbolScope, symbol: &FunctionSymbol) { if self.variables.get(&symbol.name).is_none() { + let name = self.get_name(symbol.export); + if let Some(_) = tlss.functions.get(&symbol.name) { let rf = FunctionRef { export: symbol.export, - name: symbol.name.clone(), + name: name.clone(), params: symbol .params .iter() @@ -81,7 +82,7 @@ impl TopLevelHirScope { self.variables.insert( symbol.name.clone(), Arc::new(VarRef { - name: symbol.name.clone(), + name: name.clone(), var_type: Arc::new(TypeRef::Function(rf)), }), ); @@ -96,21 +97,22 @@ impl TopLevelHirScope { tlss: &TopLevelSymbolScope, symbol: &StructSymbol, ) -> Arc { + let name = self.get_name(symbol.export); + let rf = Arc::new(TypeRef::Struct(StructRef { export: symbol.export, - name: symbol.name.clone(), + name: name.clone(), fields: symbol .fields .iter() .map(|(name, v)| (name.clone(), self.var_ref(tlss, v))) .collect(), - methods: HashMap::new(), })); self.variables.insert( symbol.name.clone(), Arc::new(VarRef { - name: symbol.name.clone(), + name: name.clone(), var_type: rf.clone(), }), ); @@ -167,4 +169,8 @@ impl TopLevelHirScope { pub fn next_var_idx(&self) -> usize { self.var_idx.fetch_add(1, Ordering::Relaxed) + 1 } + + pub fn get_name(&self, export: bool) -> String { + format!("{}{}", if export { 'V' } else { 'v' }, self.next_var_idx()) + } } diff --git a/semantic/src/scope.rs b/semantic/src/scope.rs index 116bb1d..8eada56 100644 --- a/semantic/src/scope.rs +++ b/semantic/src/scope.rs @@ -89,8 +89,6 @@ impl LocalScope { ) -> Option> { let mut current_type = self.get_type_from_expr(initial)?; - dbg!(current_type.clone(), initial, postfixes); - for postfix in postfixes { match postfix { Postfix::FieldAccess(id) => match &*current_type {