Merge pull request #9 from mist-go/hir-refactor
Refactored HIR Analysis for type checking
This commit is contained in:
+3
-4
@@ -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,
|
||||||
|
|||||||
+62
-60
@@ -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()))
|
pub fn next_var_idx(&self) -> usize {
|
||||||
} else {
|
self.var_idx.fetch_add(1, Ordering::Relaxed) + 1
|
||||||
None
|
}
|
||||||
}
|
|
||||||
|
pub fn get_name(&self, export: bool) -> String {
|
||||||
|
format!("{}{}", if export { 'V' } else { 'v' }, self.next_var_idx())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-14
@@ -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,
|
|
||||||
} => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+70
-63
@@ -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(_) => 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| r.var_type.clone()),
|
||||||
|
|
||||||
|
ast::Expression::StringLiteral(_) => self
|
||||||
|
.parent
|
||||||
|
.get_reference(&"string".to_string())
|
||||||
|
.map(|r| r.var_type.clone()),
|
||||||
|
|
||||||
|
ast::Expression::Identifier(id) => self.get_reference(id).map(|r| r.var_type.clone()),
|
||||||
|
|
||||||
|
ast::Expression::Postfix { initial, postfixes } => {
|
||||||
|
self.walk_postfixes(initial, postfixes)
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::Expression::FloatLiteral(_) => {
|
|
||||||
self.parent.get_reference(&"float".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| {
|
|
||||||
if let Reference::Type(tr) = &r {
|
|
||||||
tr.clone()
|
|
||||||
} else {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
ast::Expression::StringLiteral(_) => {
|
|
||||||
self.parent.get_reference(&"string".to_string()).map(|r| {
|
|
||||||
if let Reference::Type(tr) = &r {
|
|
||||||
tr.clone()
|
|
||||||
} else {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
},
|
|
||||||
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 ¶m_list.0 {
|
for (param_name, type_expr) in ¶m_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
@@ -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 { }
|
||||||
Reference in New Issue
Block a user