diff --git a/examples/triple_import_main.reid b/examples/triple_import_main.reid index d2660d9..fab276f 100644 --- a/examples/triple_import_main.reid +++ b/examples/triple_import_main.reid @@ -1,4 +1,6 @@ import triple_import_vec2::Vec2; import triple_import_ship::Ship; -fn main() -> i32 { return 0; } \ No newline at end of file +fn main() -> i32 { + return 0; +} \ No newline at end of file diff --git a/examples/triple_import_ship.reid b/examples/triple_import_ship.reid index c2bd7f2..2b36bcf 100644 --- a/examples/triple_import_ship.reid +++ b/examples/triple_import_ship.reid @@ -1,9 +1,17 @@ +//asd import triple_import_vec2::Vec2; struct Ship { position: Vec2, + velocity: Vec2, } + impl Ship { - pub fn foo(&self, vec: Vec2) {} + pub fn foo(&self, vec: Vec2) { + let b: Ship = Ship { + position: Vec2::zero(), + velocity: Vec2::zero(), + }; + } } \ No newline at end of file diff --git a/reid-lsp/src/analysis.rs b/reid-lsp/src/analysis.rs index 4f9770c..8ab453c 100644 --- a/reid-lsp/src/analysis.rs +++ b/reid-lsp/src/analysis.rs @@ -9,8 +9,8 @@ use reid::{ compile_module, error_raporting::{ErrorModules, ReidError}, mir::{ - self, Context, CustomTypeKey, FunctionCall, FunctionParam, IfExpression, Metadata, SourceModuleId, StructType, - TypeKind, WhileStatement, typecheck::typerefs::TypeRefs, + self, Context, CustomTypeKey, FunctionCall, FunctionDefinitionKind, FunctionParam, IfExpression, Metadata, + SourceModuleId, StructType, TypeKind, WhileStatement, typecheck::typerefs::TypeRefs, }, perform_all_passes, }; @@ -131,6 +131,7 @@ pub struct AnalysisState { pub symbol_to_token: HashMap, module_id: SourceModuleId, + module_name: String, functions: HashMap, associated_functions: HashMap<(TypeKind, String), SymbolId>, @@ -415,6 +416,7 @@ pub fn analyze_context( properties: HashMap::new(), types: HashMap::new(), module_id: module.module_id, + module_name: module.name.clone().replace(".reid", ""), }; let mut scope = AnalysisScope { @@ -474,47 +476,7 @@ pub fn analyze_context( } } - for import in &module.imports { - scope.state.init_types(&import.1, None); - if let Some((module_name, _)) = import.0.get(0) { - let (import_name, import_meta) = import.0.get(1).cloned().unwrap_or(( - String::new(), - mir::Metadata { - source_module_id: module.module_id, - range: reid::ast::token_stream::TokenRange { - start: import.1.range.end - 1, - end: import.1.range.end - 1, - }, - position: None, - }, - )); - let mut autocompletes = Vec::new(); - - if let Some((_, module)) = context.modules.iter().find(|m| m.1.name == *module_name) { - for function in &module.functions { - if !function.is_pub { - continue; - } - if function.name.starts_with(&import_name) { - autocompletes.push(Autocomplete { - text: function.name.clone(), - kind: AutocompleteKind::Function(function.parameters.clone(), function.return_type.clone()), - }); - } - } - for typedef in &module.typedefs { - if typedef.name.starts_with(&import_name) { - autocompletes.push(Autocomplete { - text: typedef.name.clone(), - kind: AutocompleteKind::Type, - }); - } - } - } - scope.state.set_autocomplete(import_meta.range.end, autocompletes); - } - } - + // First we need to initialize symbols for all types themselves correctly for typedef in &module.typedefs { if typedef.source_module != module.module_id { if let Some(state) = map.get(&typedef.source_module) { @@ -570,6 +532,47 @@ pub fn analyze_context( } } + // Afterwards we can try to assign types correctly to the fields of structs + for typedef in &module.typedefs { + if typedef.source_module != module.module_id { + continue; + } + + match &typedef.kind { + mir::TypeDefinitionKind::Struct(StructType(fields)) => { + for field in fields { + let field_idx = scope + .token_idx(&field.2, |t| matches!(t, Token::Identifier(_))) + .unwrap_or(field.2.range.end); + + let field_ty_idx = scope + .token_idx(&field.2.after(field_idx + 1), |t| matches!(t, Token::Identifier(_))) + .unwrap_or(field.2.range.end); + let field_ty_symbol = if let Some((source_id, symbol_id)) = scope.types.get(&field.1) { + scope + .state + .new_symbol(field_ty_idx, SemanticKind::Reference(*source_id, *symbol_id)) + } else { + scope.state.new_symbol(field_ty_idx, SemanticKind::Type) + }; + + scope.state.init_types( + &Metadata { + source_module_id: field.2.source_module_id, + range: TokenRange { + start: field_ty_idx, + end: field_ty_idx, + }, + position: None, + }, + Some(field.1.clone()), + ); + scope.state.set_symbol(field_ty_idx, field_ty_symbol); + } + } + } + } + for binop in &module.binop_defs { if binop.meta.source_module_id == module.module_id { for param in [&binop.lhs, &binop.rhs] { @@ -627,18 +630,7 @@ pub fn analyze_context( let mut inner_scope = scope.inner(); - for param in &function.parameters { - inner_scope.state.init_types(¶m.meta, Some(param.ty.clone())); - - if param.meta.source_module_id == module.module_id { - let param_idx = inner_scope - .token_idx(¶m.meta, |t| matches!(t, Token::Identifier(_))) - .unwrap_or(function.signature().range.end); - let param_symbol = inner_scope.state.new_symbol(param_idx, SemanticKind::Variable); - inner_scope.state.set_symbol(param_idx, param_symbol); - inner_scope.variables.insert(param.name.clone(), param_symbol); - } - } + analyze_function_parameters(context, module, function, &mut inner_scope); match &function.kind { mir::FunctionDefinitionKind::Local(block, _) => analyze_block(context, module, block, &mut inner_scope), @@ -683,17 +675,7 @@ pub fn analyze_context( let mut inner_scope = scope.inner(); - for param in &function.parameters { - inner_scope.state.init_types(¶m.meta, Some(param.ty.clone())); - if param.meta.source_module_id == module.module_id { - let idx = inner_scope - .token_idx(¶m.meta, |t| matches!(t, Token::Identifier(_))) - .unwrap_or(function.signature().range.end); - let symbol = inner_scope.state.new_symbol(idx, SemanticKind::Variable); - inner_scope.state.set_symbol(idx, symbol); - inner_scope.variables.insert(param.name.clone(), symbol); - } - } + analyze_function_parameters(context, module, function, &mut inner_scope); match &function.kind { mir::FunctionDefinitionKind::Local(block, _) => analyze_block(context, module, block, &mut inner_scope), @@ -702,6 +684,75 @@ pub fn analyze_context( }; } + for import in &module.imports { + scope.state.init_types(&import.1, None); + if let Some((module_name, _)) = import.0.get(0) { + let module_idx = scope + .token_idx(&import.1, |t| matches!(t, Token::Identifier(_))) + .unwrap_or(import.1.range.end - 1); + let import_idx = scope + .token_idx(&import.1.after(module_idx + 1), |t| matches!(t, Token::Identifier(_))) + .unwrap_or(import.1.range.end - 1); + + let (import_name, import_meta) = import.0.get(1).cloned().unwrap_or(( + String::new(), + mir::Metadata { + source_module_id: module.module_id, + range: reid::ast::token_stream::TokenRange { + start: import_idx, + end: import_idx, + }, + position: None, + }, + )); + let mut autocompletes = Vec::new(); + + if let Some((_, module)) = context.modules.iter().find(|m| m.1.name == *module_name) { + for function in &module.functions { + if !function.is_pub { + continue; + } + if function.name.starts_with(&import_name) { + autocompletes.push(Autocomplete { + text: function.name.clone(), + kind: AutocompleteKind::Function(function.parameters.clone(), function.return_type.clone()), + }); + } + } + for typedef in &module.typedefs { + if typedef.name.starts_with(&import_name) { + autocompletes.push(Autocomplete { + text: typedef.name.clone(), + kind: AutocompleteKind::Type, + }); + } + } + } + + let symbol = if let Some((source_id, symbol_id)) = scope.functions.get(&import_name) { + scope + .state + .new_symbol(import_idx, SemanticKind::Reference(*source_id, *symbol_id)) + } else if let Some(module_source) = scope.map.values().find(|s| s.module_name == *module_name) { + if let Some((source_id, symbol_id)) = scope.types.get(&TypeKind::CustomType(CustomTypeKey( + import_name.clone(), + module_source.module_id, + ))) { + scope + .state + .new_symbol(import_idx, SemanticKind::Reference(*source_id, *symbol_id)) + } else { + scope.state.new_symbol(import_idx, SemanticKind::Default) + } + } else { + scope.state.new_symbol(import_idx, SemanticKind::Default) + }; + scope.state.set_symbol(import_idx, symbol); + + scope.state.set_autocomplete(import_meta.range.end, autocompletes); + } + } + StaticAnalysis { tokens: module.tokens.clone(), state, @@ -709,6 +760,41 @@ pub fn analyze_context( } } +pub fn analyze_function_parameters( + context: &mir::Context, + module: &mir::Module, + function: &mir::FunctionDefinition, + scope: &mut AnalysisScope, +) { + for param in &function.parameters { + scope.state.init_types(¶m.meta, Some(param.ty.clone())); + + if param.meta.source_module_id == module.module_id { + let param_var_idx = scope + .token_idx(¶m.meta, |t| matches!(t, Token::Identifier(_))) + .unwrap_or(function.signature().range.end); + let param_var_symbol = scope.state.new_symbol(param_var_idx, SemanticKind::Variable); + scope.state.set_symbol(param_var_idx, param_var_symbol); + scope.variables.insert(param.name.clone(), param_var_symbol); + + let param_ty_idx = scope + .token_idx(¶m.meta.after(param_var_idx + 1), |t| { + matches!(t, Token::Identifier(_)) + }) + .unwrap_or(function.signature().range.end); + + let param_ty_symbol = scope.state.new_symbol( + param_ty_idx, + match scope.types.get(¶m.ty) { + Some((source_id, symbol_id)) => SemanticKind::Reference(*source_id, *symbol_id), + None => SemanticKind::Type, + }, + ); + scope.state.set_symbol(param_ty_idx, param_ty_symbol); + } + } +} + pub fn analyze_block( context: &mir::Context, source_module: &mir::Module, @@ -734,6 +820,21 @@ pub fn analyze_block( scope.state.set_symbol(idx, symbol); scope.variables.insert(named_variable_ref.1.clone(), symbol); + let ty_idx = scope.token_idx(&named_variable_ref.2.after(idx + 1), |t| { + matches!(t, Token::Identifier(_)) + }); + dbg!(ty_idx); + if let Some(ty_idx) = ty_idx { + let ty_symbol = if let Some((source_id, symbol_id)) = scope.types.get(&named_variable_ref.0) { + scope + .state + .new_symbol(ty_idx, SemanticKind::Reference(*source_id, *symbol_id)) + } else { + scope.state.new_symbol(ty_idx, SemanticKind::Type) + }; + scope.state.set_symbol(ty_idx, ty_symbol); + } + analyze_expr(context, source_module, expression, scope); } mir::StmtKind::Set(lhs, rhs) => { @@ -859,10 +960,10 @@ pub fn analyze_expr( .token_idx(&expr.1, |t| matches!(t, Token::Identifier(_))) .unwrap_or(expr.1.range.end); - let struct_symbol = if let Some(symbol_id) = scope.state.types.get(&struct_type) { + let struct_symbol = if let Some((source_id, symbol_id)) = scope.types.get(&struct_type) { scope .state - .new_symbol(struct_idx, SemanticKind::Reference(source_module.module_id, *symbol_id)) + .new_symbol(struct_idx, SemanticKind::Reference(*source_id, *symbol_id)) } else { scope.state.new_symbol(struct_idx, SemanticKind::Struct) }; diff --git a/reid/src/mir/linker.rs b/reid/src/mir/linker.rs index d2c65f1..52cdf99 100644 --- a/reid/src/mir/linker.rs +++ b/reid/src/mir/linker.rs @@ -546,11 +546,9 @@ impl<'map> Pass for LinkerPass<'map> { let mod_id = state.scope.module_id.unwrap(); let foreign_types = &state.scope.data.foreign_types.get(&mod_id); if let Some(foreign_types) = foreign_types { - dbg!(state.scope.module_id, foreign_types, &function.parameters); function.return_type = function.return_type.update_imported(*foreign_types); for param in function.parameters.iter_mut() { param.ty = param.ty.update_imported(foreign_types); - dbg!(¶m.ty); } } Ok(()) diff --git a/reid/src/mir/mod.rs b/reid/src/mir/mod.rs index 13bfb97..b089413 100644 --- a/reid/src/mir/mod.rs +++ b/reid/src/mir/mod.rs @@ -55,6 +55,28 @@ impl Metadata { pub fn contains(&self, token_idx: usize) -> bool { return token_idx >= self.range.start && token_idx <= self.range.end; } + + pub fn after(&self, cutoff: usize) -> Metadata { + Metadata { + source_module_id: self.source_module_id, + range: TokenRange { + start: cutoff.max(self.range.start), + end: cutoff.max(self.range.end), + }, + position: None, + } + } + + pub fn before(&self, cutoff: usize) -> Metadata { + Metadata { + source_module_id: self.source_module_id, + range: TokenRange { + start: cutoff.min(self.range.start), + end: cutoff.min(self.range.end), + }, + position: None, + } + } } impl std::ops::Add for Metadata {