Merge pull request #9 from mist-go/hir-refactor

Refactored HIR Analysis for type checking
This commit is contained in:
2026-04-16 10:33:10 +02:00
committed by GitHub
5 changed files with 145 additions and 145 deletions
+3 -4
View File
@@ -167,10 +167,9 @@ impl Statement {
let kind_pair = inner.next().unwrap(); // let/const/var let kind_pair = inner.next().unwrap(); // let/const/var
let name_pair = inner.next().unwrap(); // identifier let name_pair = inner.next().unwrap(); // identifier
let init = inner.next().map(|expr_pair| { println!("{:#?}", inner);
// expects "=" expr
Expression::from_pair(expr_pair.into_inner().next().unwrap()) let init = inner.next().map(Expression::from_pair);
});
let kind = match kind_pair.as_str() { let kind = match kind_pair.as_str() {
"let" => VarKind::Let, "let" => VarKind::Let,
+61 -59
View File
@@ -1,13 +1,17 @@
use std::{collections::HashMap, sync::Arc}; use std::{
collections::HashMap,
use crate::{ sync::{
scope::Reference, Arc,
top_level::{FunctionSymbol, StructSymbol, TopLevelSymbolScope, TypeSymbol, VarSymbol}, atomic::{AtomicUsize, Ordering},
},
}; };
use crate::top_level::{FunctionSymbol, StructSymbol, TopLevelSymbolScope, TypeSymbol, VarSymbol};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum TypeRef { pub enum TypeRef {
Struct(StructRef), Struct(StructRef),
Function(FunctionRef),
Int, Int,
} }
@@ -30,20 +34,19 @@ pub struct StructRef {
pub export: bool, pub export: bool,
pub name: String, pub name: String,
pub fields: HashMap<String, Arc<VarRef>>, pub fields: HashMap<String, Arc<VarRef>>,
pub methods: HashMap<String, FunctionRef>,
} }
#[derive(Debug)] #[derive(Debug)]
pub struct TopLevelHirScope { pub struct TopLevelHirScope {
pub types: HashMap<String, Arc<TypeRef>>, pub variables: HashMap<String, Arc<VarRef>>,
pub functions: HashMap<String, Arc<FunctionRef>>, pub var_idx: AtomicUsize,
} }
impl TopLevelHirScope { impl TopLevelHirScope {
pub fn from_tlss(tlss: &TopLevelSymbolScope) -> Self { pub fn from_tlss(tlss: &TopLevelSymbolScope) -> Self {
let mut scope = Self { let mut scope = Self {
types: HashMap::new(), variables: HashMap::new(),
functions: HashMap::new(), var_idx: AtomicUsize::new(0),
}; };
for (_, symbol) in &tlss.functions { for (_, symbol) in &tlss.functions {
@@ -57,18 +60,14 @@ impl TopLevelHirScope {
scope scope
} }
pub fn function_ref( pub fn function_ref(&mut self, tlss: &TopLevelSymbolScope, symbol: &FunctionSymbol) {
&mut self, if self.variables.get(&symbol.name).is_none() {
tlss: &TopLevelSymbolScope, let name = self.get_name(symbol.export);
symbol: &FunctionSymbol,
) -> Arc<FunctionRef> {
if let Some(rf) = self.functions.get(&symbol.name) {
rf.clone()
} else {
if let Some(_) = tlss.functions.get(&symbol.name) { if let Some(_) = tlss.functions.get(&symbol.name) {
let rf = Arc::new(FunctionRef { let rf = FunctionRef {
export: symbol.export, export: symbol.export,
name: symbol.name.clone(), name: name.clone(),
params: symbol params: symbol
.params .params
.iter() .iter()
@@ -78,11 +77,15 @@ impl TopLevelHirScope {
.return_type .return_type
.clone() .clone()
.map(|rt| self.type_ref(tlss, &rt)), .map(|rt| self.type_ref(tlss, &rt)),
}); };
self.functions.insert(symbol.name.clone(), rf.clone()); self.variables.insert(
symbol.name.clone(),
rf Arc::new(VarRef {
name: name.clone(),
var_type: Arc::new(TypeRef::Function(rf)),
}),
);
} else { } else {
unimplemented!() unimplemented!()
} }
@@ -94,18 +97,25 @@ impl TopLevelHirScope {
tlss: &TopLevelSymbolScope, tlss: &TopLevelSymbolScope,
symbol: &StructSymbol, symbol: &StructSymbol,
) -> Arc<TypeRef> { ) -> Arc<TypeRef> {
let name = self.get_name(symbol.export);
let rf = Arc::new(TypeRef::Struct(StructRef { let rf = Arc::new(TypeRef::Struct(StructRef {
export: symbol.export, export: symbol.export,
name: symbol.name.clone(), name: name.clone(),
fields: symbol fields: symbol
.fields .fields
.iter() .iter()
.map(|(name, v)| (name.clone(), self.var_ref(tlss, v))) .map(|(name, v)| (name.clone(), self.var_ref(tlss, v)))
.collect(), .collect(),
methods: HashMap::new(),
})); }));
self.types.insert(symbol.name.clone(), rf.clone()); self.variables.insert(
symbol.name.clone(),
Arc::new(VarRef {
name: name.clone(),
var_type: rf.clone(),
}),
);
rf rf
} }
@@ -118,40 +128,30 @@ impl TopLevelHirScope {
} }
pub fn type_ref(&mut self, tlss: &TopLevelSymbolScope, symbol: &TypeSymbol) -> Arc<TypeRef> { pub fn type_ref(&mut self, tlss: &TopLevelSymbolScope, symbol: &TypeSymbol) -> Arc<TypeRef> {
if let Some(rf) = self.types.get(&symbol.0) { if let Some(var_ref) = self.variables.get(&symbol.0) {
rf.clone() var_ref.var_type.clone()
} else { } else {
if let Some(tlss_rf) = tlss.structs.get(&symbol.0) { if let Some(tlss_rf) = tlss.structs.get(&symbol.0) {
let rf = Arc::new(TypeRef::Struct(StructRef { let struct_ref = self.struct_ref(tlss, tlss_rf);
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(),
}));
self.types.insert(symbol.0.clone(), rf.clone()); let var_ref = Arc::new(VarRef {
name: symbol.0.clone(),
var_type: struct_ref,
});
self.variables.insert(symbol.0.clone(), var_ref.clone());
rf var_ref.var_type.clone()
} else { } else {
match symbol.0.as_str() { match symbol.0.as_str() {
"int" => { "int" => {
let rf = Arc::new(TypeRef::Int); let var_ref = Arc::new(VarRef {
name: symbol.0.clone(),
var_type: Arc::new(TypeRef::Int),
});
self.types.insert(symbol.0.clone(), rf.clone()); self.variables.insert(symbol.0.clone(), var_ref.clone());
rf var_ref.var_type.clone()
} }
_ => { _ => {
@@ -162,13 +162,15 @@ impl TopLevelHirScope {
} }
} }
pub fn get_reference(&self, name: &String) -> Option<Reference> { pub fn get_reference(&self, name: &String) -> Option<Arc<VarRef>> {
if let Some(r) = self.functions.get(name) { self.variables.get(name).cloned()
Some(Reference::Func(r.clone()))
} else if let Some(r) = self.types.get(name) {
Some(Reference::Type(r.clone()))
} else {
None
} }
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())
} }
} }
+2 -14
View File
@@ -11,27 +11,15 @@ pub fn walk_ast(top_scope: Arc<Scope>, tl: &mut Vec<parser::ast::TopLevel>) {
match tl { match tl {
parser::ast::TopLevel::Import(_) => unimplemented!(), parser::ast::TopLevel::Import(_) => unimplemented!(),
parser::ast::TopLevel::FunctionDecl { parser::ast::TopLevel::FunctionDecl { params, body, .. } => {
export,
name,
params,
return_type,
body,
} => {
let scope = LocalScope::new(top_scope.clone()); let scope = LocalScope::new(top_scope.clone());
scope.with_params(params); scope.with_params(params);
scope.with_block(body); scope.with_block(body);
println!("{:?}", scope);
} }
parser::ast::TopLevel::StructDecl { parser::ast::TopLevel::StructDecl { .. } => {}
export,
name,
fields,
} => {}
} }
} }
} }
+66 -59
View File
@@ -3,20 +3,13 @@ use std::{
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
use parser::ast::{self, ParamList, Statement}; use parser::ast::{self, ParamList, Postfix, Statement};
use crate::{ use crate::{
hir::{FunctionRef, TopLevelHirScope, TypeRef, VarRef}, hir::{TopLevelHirScope, TypeRef, VarRef},
top_level::TopLevelSymbolScope, top_level::TopLevelSymbolScope,
}; };
#[derive(Clone, Debug)]
pub enum Reference {
Type(Arc<TypeRef>),
Var(Arc<VarRef>),
Func(Arc<FunctionRef>),
}
#[derive(Debug)] #[derive(Debug)]
pub enum Scope { pub enum Scope {
TopLevel(TopLevelHirScope), TopLevel(TopLevelHirScope),
@@ -29,12 +22,19 @@ impl Scope {
Arc::new(Self::TopLevel(TopLevelHirScope::from_tlss(&tl))) Arc::new(Self::TopLevel(TopLevelHirScope::from_tlss(&tl)))
} }
pub fn get_reference(&self, name: &String) -> Option<Reference> { pub fn get_reference(&self, name: &String) -> Option<Arc<VarRef>> {
match self { match self {
Scope::TopLevel(tl) => tl.get_reference(name), Scope::TopLevel(tl) => tl.get_reference(name),
Scope::Local(l) => l.get_reference(name), 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)] #[derive(Debug)]
@@ -51,13 +51,12 @@ impl LocalScope {
}) })
} }
pub fn get_reference(&self, name: &String) -> Option<Reference> { pub fn get_reference(&self, name: &String) -> Option<Arc<VarRef>> {
self.variables self.variables
.lock() .lock()
.unwrap() .unwrap()
.get(name) .get(name)
.cloned() .cloned()
.map(Reference::Var)
.or_else(|| self.parent.get_reference(name)) .or_else(|| self.parent.get_reference(name))
} }
@@ -83,73 +82,81 @@ impl LocalScope {
} }
} }
pub fn walk_postfixes(
self: &Arc<Self>,
initial: &Box<ast::Expression>,
postfixes: &Vec<Postfix>,
) -> Option<Arc<TypeRef>> {
let mut current_type = self.get_type_from_expr(initial)?;
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!(),
},
Postfix::Call(_args) => match &*current_type {
TypeRef::Function(s) => {
// TODO: arg checking
current_type = s.return_type.clone()?;
}
_ => unimplemented!(),
},
_ => unimplemented!(),
}
}
Some(current_type)
}
pub fn get_type_from_expr(self: &Arc<Self>, expr: &ast::Expression) -> Option<Arc<TypeRef>> { pub fn get_type_from_expr(self: &Arc<Self>, expr: &ast::Expression) -> Option<Arc<TypeRef>> {
match expr { match expr {
ast::Expression::IntLiteral(_) => { ast::Expression::IntLiteral(_) => self
self.parent.get_reference(&"int".to_string()).map(|r| { .parent
if let Reference::Type(tr) = &r { .get_reference(&"int".to_string())
tr.clone() .map(|r| r.var_type.clone()),
} else {
unimplemented!()
}
})
}
ast::Expression::FloatLiteral(_) => { ast::Expression::FloatLiteral(_) => self
self.parent.get_reference(&"float".to_string()).map(|r| { .parent
if let Reference::Type(tr) = &r { .get_reference(&"float".to_string())
tr.clone() .map(|r| r.var_type.clone()),
} else {
unimplemented!()
}
})
}
ast::Expression::BoolLiteral(_) => { ast::Expression::BoolLiteral(_) => self
self.parent.get_reference(&"bool".to_string()).map(|r| { .parent
if let Reference::Type(tr) = &r { .get_reference(&"bool".to_string())
tr.clone() .map(|r| r.var_type.clone()),
} else {
unimplemented!()
}
})
}
ast::Expression::StringLiteral(_) => { ast::Expression::StringLiteral(_) => self
self.parent.get_reference(&"string".to_string()).map(|r| { .parent
if let Reference::Type(tr) = &r { .get_reference(&"string".to_string())
tr.clone() .map(|r| r.var_type.clone()),
} else {
unimplemented!()
}
})
}
ast::Expression::Identifier(id) => match self.get_reference(id) { ast::Expression::Identifier(id) => self.get_reference(id).map(|r| r.var_type.clone()),
Some(Reference::Var(var_ref)) => Some(var_ref.var_type.clone()),
Some(Reference::Func(func_ref)) => func_ref.return_type.clone(),
_ => None,
},
_ => unimplemented!(), ast::Expression::Postfix { initial, postfixes } => {
self.walk_postfixes(initial, postfixes)
}
} }
} }
pub fn with_params(self: &Arc<Self>, param_list: &ParamList) { pub fn with_params(self: &Arc<Self>, param_list: &ParamList) {
for (param_name, type_expr) in &param_list.0 { for (param_name, type_expr) in &param_list.0 {
match type_expr { match type_expr {
parser::ast::TypeExpr::Identifier(id) => match self.parent.get_reference(id) { parser::ast::TypeExpr::Identifier(id) => {
Some(Reference::Type(type_ref)) => { if let Some(var_type) =
self.parent.get_reference(id).map(|r| r.var_type.clone())
{
self.variables.lock().unwrap().insert( self.variables.lock().unwrap().insert(
param_name.clone(), param_name.clone(),
Arc::new(VarRef { Arc::new(VarRef {
var_type: type_ref, var_type,
name: param_name.clone(), name: param_name.clone(),
}), }),
); );
} }
_ => unimplemented!(), }
},
} }
} }
} }
+8 -4
View File
@@ -1,5 +1,9 @@
function add(a: int, b: int) { struct Test {
let myVar = 10; x: int
let test = myVar;
} }
function add() {
let output = test();
}
function test(): int { }