From 7d3aaa143a42442ef892097fb68a087d9389fa31 Mon Sep 17 00:00:00 2001 From: sofia Date: Tue, 29 Jul 2025 20:44:15 +0300 Subject: [PATCH] Start adding type-information to tooltips --- reid-lsp/src/main.rs | 115 ++++++++++++++++++++++++++++++++++------ reid/Cargo.toml | 1 + reid/src/ast/lexer.rs | 4 +- reid/src/ast/mod.rs | 2 +- reid/src/ast/parse.rs | 10 ++-- reid/src/ast/process.rs | 4 +- reid/src/lib.rs | 3 ++ reid/src/mir/mod.rs | 12 +++++ 8 files changed, 125 insertions(+), 26 deletions(-) diff --git a/reid-lsp/src/main.rs b/reid-lsp/src/main.rs index d888365..7cffd37 100644 --- a/reid-lsp/src/main.rs +++ b/reid-lsp/src/main.rs @@ -1,8 +1,10 @@ +use std::collections::HashMap; use std::path::PathBuf; use dashmap::DashMap; use reid::ast::lexer::{FullToken, Position}; -use reid::{compile_module, parse_module}; +use reid::mir::{self, Context, StructType, TypeKind}; +use reid::{compile_module, parse_module, perform_all_passes}; use tower_lsp::jsonrpc::Result; use tower_lsp::lsp_types::{ self, CompletionItem, CompletionOptions, CompletionParams, CompletionResponse, Diagnostic, DiagnosticSeverity, @@ -18,6 +20,7 @@ struct Backend { client: Client, tokens: DashMap>, ast: DashMap, + types: DashMap>>, } #[tower_lsp::async_trait] @@ -72,7 +75,7 @@ impl LanguageServer for Backend { async fn hover(&self, params: HoverParams) -> Result> { let path = PathBuf::from(params.text_document_position_params.text_document.uri.path()); let file_name = path.file_name().unwrap().to_str().unwrap().to_owned(); - let tokens = self.tokens.get(&file_name).unwrap(); + let tokens = self.tokens.get(&file_name); let position = params.text_document_position_params.position; self.client @@ -81,20 +84,33 @@ impl LanguageServer for Backend { format!("line {}, col {}", position.line, position.character), ) .await; - let token = tokens.iter().find(|tok| { - tok.position.1 == position.line + 1 - && (tok.position.0 <= position.character + 1 - && (tok.position.0 + tok.token.len() as u32) > position.character + 1) - }); + let token = if let Some(tokens) = &tokens { + tokens.iter().find(|tok| { + tok.position.1 == position.line + 1 + && (tok.position.0 <= position.character + 1 + && (tok.position.0 + tok.token.len() as u32) > position.character + 1) + }) + } else { + None + }; + + let ty = if let Some(token) = token { + if let Some(ty) = self.types.get(&file_name).unwrap().get(token) { + ty.clone() + } else { + None + } + } else { + None + }; Ok(Some(Hover { - contents: HoverContents::Scalar(MarkedString::String(format!("{:?}", token))), + contents: HoverContents::Scalar(MarkedString::String(format!("{:?}", ty))), range: None, })) } async fn did_open(&self, params: DidOpenTextDocumentParams) { - self.client.log_message(MessageType::INFO, "opened!").await; self.recompile(TextDocumentItem { uri: params.text_document.uri, language_id: params.text_document.language_id, @@ -105,7 +121,6 @@ impl LanguageServer for Backend { } async fn did_change(&self, params: DidChangeTextDocumentParams) { - self.client.log_message(MessageType::INFO, "changed!").await; self.recompile(TextDocumentItem { text: params.content_changes[0].text.clone(), uri: params.text_document.uri, @@ -124,6 +139,7 @@ impl Backend { let mut reid_error = None; let mut tokens = None; + let token_types = DashMap::new(); match parse_module(¶ms.text, file_name.clone(), &mut map) { Ok(module) => { @@ -131,14 +147,34 @@ impl Backend { .log_message(MessageType::INFO, format!("successfully parsed!")) .await; tokens = Some(module.1.clone()); - match compile_module(module.0, module.1, &mut map, Some(path), true) { - Ok(_) => {} + match compile_module(module.0, module.1, &mut map, Some(path.clone()), true) { + Ok(module) => { + let module_id = module.module_id; + let mut context = Context::from(vec![module], path.parent().unwrap().to_owned()); + match perform_all_passes(&mut context, &mut map) { + Ok(_) => { + for module in context.modules.values() { + if module.module_id != module_id { + continue; + } + for (idx, token) in module.tokens.iter().enumerate() { + token_types.insert(token.clone(), find_type_in_context(&module, idx)); + } + } + } + Err(e) => { + reid_error = Some(e); + } + } + } Err(e) => { reid_error = Some(e); } } } - Err(_) => {} + Err(e) => { + reid_error = Some(e); + } } if let Some(tokens) = &tokens { @@ -151,9 +187,6 @@ impl Backend { .into_position(&tokens) .unwrap_or((Position(0, 0), Position(0, 0))); self.client.log_message(MessageType::INFO, format!("{:?}", &meta)).await; - self.client - .log_message(MessageType::INFO, format!("{:?}", &tokens)) - .await; self.client .log_message(MessageType::INFO, format!("{:?}", &positions)) .await; @@ -193,6 +226,7 @@ impl Backend { if let Some(tokens) = tokens.take() { self.tokens.insert(file_name.clone(), tokens); } + self.types.insert(file_name.clone(), token_types); } } @@ -205,6 +239,55 @@ async fn main() { client, ast: DashMap::new(), tokens: DashMap::new(), + types: DashMap::new(), }); Server::new(stdin, stdout, socket).serve(service).await; } + +pub fn find_type_in_context(module: &mir::Module, token_idx: usize) -> Option { + for import in &module.imports { + if import.1.contains(token_idx) { + return None; + } + } + for typedef in &module.typedefs { + if !typedef.meta.contains(token_idx) { + continue; + } + + match &typedef.kind { + mir::TypeDefinitionKind::Struct(StructType(fields)) => { + for field in fields { + if field.2.contains(token_idx) { + return Some(field.1.clone()); + } + } + } + } + } + + for function in &module.functions { + if !(function.signature() + function.block_meta()).contains(token_idx) { + continue; + } + + for param in &function.parameters { + if param.meta.contains(token_idx) { + return Some(param.ty.clone()); + } + } + + return match &function.kind { + mir::FunctionDefinitionKind::Local(block, _) => find_type_in_block(&block, token_idx), + mir::FunctionDefinitionKind::Extern(_) => None, + mir::FunctionDefinitionKind::Intrinsic(_) => None, + }; + } + None +} + +pub fn find_type_in_block(block: &mir::Block, token_idx: usize) -> Option { + for statement in &block.statements {} + + None +} diff --git a/reid/Cargo.toml b/reid/Cargo.toml index bbd577b..cab1b43 100644 --- a/reid/Cargo.toml +++ b/reid/Cargo.toml @@ -11,6 +11,7 @@ default = ["color"] color = ["colored"] log_output = [] +context_debug = [] [dependencies] ## Make it easier to generate errors diff --git a/reid/src/ast/lexer.rs b/reid/src/ast/lexer.rs index b300780..bd32a88 100644 --- a/reid/src/ast/lexer.rs +++ b/reid/src/ast/lexer.rs @@ -7,7 +7,7 @@ static HEXADECIMAL_NUMERICS: &[char] = &[ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', ]; -#[derive(Eq, PartialEq, Clone, PartialOrd, Ord)] +#[derive(Eq, PartialEq, Clone, PartialOrd, Ord, Hash)] pub enum Token { /// Values Identifier(String), @@ -211,7 +211,7 @@ impl std::fmt::Debug for Token { } /// A token with a position -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct FullToken { pub token: Token, pub position: Position, diff --git a/reid/src/ast/mod.rs b/reid/src/ast/mod.rs index 4fd9c56..fd35fd5 100644 --- a/reid/src/ast/mod.rs +++ b/reid/src/ast/mod.rs @@ -193,7 +193,7 @@ pub struct FunctionDefinition(pub FunctionSignature, pub bool, pub Block, pub To pub struct FunctionSignature { pub name: String, pub self_kind: SelfKind, - pub params: Vec<(String, Type)>, + pub params: Vec<(String, Type, TokenRange)>, pub return_type: Option, #[allow(dead_code)] pub range: TokenRange, diff --git a/reid/src/ast/parse.rs b/reid/src/ast/parse.rs index 6c7c82e..f11a8a7 100644 --- a/reid/src/ast/parse.rs +++ b/reid/src/ast/parse.rs @@ -668,7 +668,7 @@ impl Parse for FunctionDefinition { } #[derive(Debug)] -struct FunctionParam(String, Type); +struct FunctionParam(String, Type, TokenRange); impl Parse for FunctionParam { fn parse(mut stream: TokenStream) -> Result { @@ -676,7 +676,7 @@ impl Parse for FunctionParam { return Err(stream.expected_err("parameter name")?); }; stream.expect(Token::Colon)?; - Ok(FunctionParam(arg_name, stream.parse()?)) + Ok(FunctionParam(arg_name, stream.parse()?, stream.get_range().unwrap())) } } @@ -738,11 +738,11 @@ impl Parse for FunctionSignature { match &self_kind { SelfKind::None => { if let Ok(param) = stream.parse::() { - params.push((param.0, param.1)); + params.push((param.0, param.1, param.2)); while let Some(Token::Comma) = stream.peek() { stream.next(); let param = stream.parse::()?; - params.push((param.0, param.1)); + params.push((param.0, param.1, param.2)); } } } @@ -750,7 +750,7 @@ impl Parse for FunctionSignature { while let Some(Token::Comma) = stream.peek() { stream.next(); let param = stream.parse::()?; - params.push((param.0, param.1)); + params.push((param.0, param.1, param.2)); } } } diff --git a/reid/src/ast/process.rs b/reid/src/ast/process.rs index a4c7cbe..58171aa 100644 --- a/reid/src/ast/process.rs +++ b/reid/src/ast/process.rs @@ -51,7 +51,7 @@ impl ast::Module { .map(|p| mir::FunctionParam { name: p.0, ty: p.1 .0.into_mir(module_id), - meta: p.1 .1.as_meta(module_id), + meta: p.2.as_meta(module_id), }) .collect(), kind: mir::FunctionDefinitionKind::Extern(false), @@ -164,7 +164,7 @@ impl ast::FunctionDefinition { params.extend(signature.params.iter().cloned().map(|p| FunctionParam { name: p.0, ty: p.1 .0.into_mir(module_id), - meta: p.1 .1.as_meta(module_id), + meta: p.2.as_meta(module_id), })); mir::FunctionDefinition { name: signature.name.clone(), diff --git a/reid/src/lib.rs b/reid/src/lib.rs index ce6ec5f..f72bda2 100644 --- a/reid/src/lib.rs +++ b/reid/src/lib.rs @@ -273,6 +273,9 @@ pub fn perform_all_passes<'map>( )); } + #[cfg(feature = "context_debug")] + dbg!(&context); + Ok(()) } diff --git a/reid/src/mir/mod.rs b/reid/src/mir/mod.rs index e4c3054..c061722 100644 --- a/reid/src/mir/mod.rs +++ b/reid/src/mir/mod.rs @@ -43,6 +43,18 @@ impl Metadata { pub fn into_positions(&self, tokens: &Vec) -> Option<(Position, Position)> { self.range.into_position(tokens) } + + pub fn is_after(&self, token_idx: usize) -> bool { + return token_idx < self.range.start; + } + + pub fn is_before(&self, token_idx: usize) -> bool { + return token_idx > self.range.end; + } + + pub fn contains(&self, token_idx: usize) -> bool { + return token_idx >= self.range.start && token_idx <= self.range.end; + } } impl std::ops::Add for Metadata {