Skip to content

Commit

Permalink
Add LSP support for template arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
VonTum committed Jun 27, 2024
1 parent bda34d4 commit 2c9649f
Show file tree
Hide file tree
Showing 11 changed files with 251 additions and 114 deletions.
7 changes: 0 additions & 7 deletions src/abstract_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,6 @@ impl DomainType {
pub fn new_unset() -> DomainType {
DomainType::Physical(DomainID::PLACEHOLDER)
}
pub fn physical_to_string(physical_id : DomainID, interfaces : &FlatAlloc<Interface, DomainIDMarker>) -> String {
if let Some(interf) = interfaces.get(physical_id) {
format!("{{{}}}", interf.name)
} else {
format!("{{unnamed domain {}}}", physical_id.get_hidden_value())
}
}
}

#[derive(Debug, Clone)]
Expand Down
2 changes: 1 addition & 1 deletion src/codegen_fallback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ impl<'g, 'out, Stream : std::fmt::Write> CodeGenerationContext<'g, 'out, Stream>

if let Instruction::Declaration(wire_decl) = &self.md.instructions[w.original_instruction] {
// Don't print named inputs and outputs, already did that in interface
if let DeclarationPortInfo::RegularPort { is_input: _ } = wire_decl.is_port {
if let DeclarationPortInfo::RegularPort { is_input: _, port_id:_ } = wire_decl.is_port {
continue;
}
}
Expand Down
28 changes: 23 additions & 5 deletions src/dev_aid/lsp/hover_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::borrow::Cow;
use lsp_types::{LanguageString, MarkedString};

use crate::{
abstract_type::DomainType, flattening::{DeclarationPortInfo, FlatID, IdentifierType, InterfaceToDomainMap, Module}, instantiation::{SubModuleOrWire, CALCULATE_LATENCY_LATER}, linker::{FileData, LinkInfo, Linker, NameElem}, parser::Documentation, to_string::map_to_type_names
abstract_type::DomainType, flattening::{DeclarationPortInfo, FlatID, IdentifierType, InterfaceToDomainMap, Module}, instantiation::{SubModuleOrWire, CALCULATE_LATENCY_LATER}, linker::{FileData, LinkInfo, Linker, NameElem}, parser::Documentation, template::TemplateInputKind
};

use super::tree_walk::{InModule, LocationInfo};
Expand Down Expand Up @@ -78,7 +78,7 @@ pub fn hover(info: LocationInfo, linker: &Linker, file_data: &FileData) -> Vec<M
details_vec.push(ds);
}
match decl.is_port {
DeclarationPortInfo::RegularPort { is_input } => details_vec.push(if is_input {"input"} else {"output"}),
DeclarationPortInfo::RegularPort { is_input, port_id:_ } => details_vec.push(if is_input {"input"} else {"output"}),
DeclarationPortInfo::NotPort => {},
DeclarationPortInfo::GenerativeInput(_) => details_vec.push("input") // "gen" in "input gen" is covered by decl.identifier_type
}
Expand All @@ -89,7 +89,7 @@ pub fn hover(info: LocationInfo, linker: &Linker, file_data: &FileData) -> Vec<M
IdentifierType::Generative => {details_vec.push("gen")}
}

let typ_str = decl.typ.typ.to_string(&linker.types, &map_to_type_names(&md.link_info.template_arguments));
let typ_str = decl.typ.typ.to_string(&linker.types, &md.link_info.template_arguments);
details_vec.push(&typ_str);

details_vec.push(&decl.name);
Expand Down Expand Up @@ -126,12 +126,30 @@ pub fn hover(info: LocationInfo, linker: &Linker, file_data: &FileData) -> Vec<M
}
}
};
details_vec.push(Cow::Owned(wire.typ.typ.to_string(&linker.types, &map_to_type_names(&md.link_info.template_arguments))));
details_vec.push(Cow::Owned(wire.typ.typ.to_string(&linker.types, &md.link_info.template_arguments)));
hover.sus_code(details_vec.join(" "));
hover.gather_hover_infos(md, id, wire.typ.domain.is_generative());
}
LocationInfo::Type(typ, link_info) => {
hover.sus_code(typ.to_type().to_string(&linker.types, &map_to_type_names(&link_info.template_arguments)));
hover.sus_code(typ.to_type().to_string(&linker.types, &link_info.template_arguments));
}
LocationInfo::TemplateInput(in_obj, link_info, _template_id, template_arg) => {
match &template_arg.kind {
TemplateInputKind::Type { default_value } => {
if let Some(default_typ) = default_value {
hover.monospace(format!("type param '{}' = {}", template_arg.name, default_typ.to_string(&linker.types, &link_info.template_arguments)));
} else {
hover.monospace(format!("type param '{}'", template_arg.name));
}
}
TemplateInputKind::Generative { decl_span:_, declaration_instruction } => {
let NameElem::Module(md_id) = in_obj else {todo!("Non-module template args")};
let md = &linker.modules[md_id];
let decl = md.instructions[*declaration_instruction].unwrap_wire_declaration();
hover.sus_code(format!("input gen {} {}", template_arg.name, decl.typ_expr.to_string(&linker.types, &link_info.template_arguments)));
hover.gather_hover_infos(md, *declaration_instruction, true);
}
}
}
LocationInfo::Global(global) => {
if let Some(link_info) = linker.get_link_info(global) {
Expand Down
3 changes: 3 additions & 0 deletions src/dev_aid/lsp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,9 @@ fn handle_request(method : &str, params : serde_json::Value, file_cache : &mut L
}
LocationInfo::InModule(_, _, _, InModule::Temporary(_)) => {}
LocationInfo::Type(_, _) => {}
LocationInfo::TemplateInput(_, link_info, _, template_arg) => {
goto_definition_list.push((template_arg.name_span, link_info.file))
}
LocationInfo::Global(id) => {
if let Some(link_info) = file_cache.linker.get_link_info(id) {
goto_definition_list.push((link_info.name_span, link_info.file));
Expand Down
8 changes: 7 additions & 1 deletion src/dev_aid/lsp/semantic_tokens.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

use lsp_types::{Position, SemanticToken, SemanticTokenModifier, SemanticTokenType, SemanticTokensFullOptions, SemanticTokensLegend, SemanticTokensOptions, SemanticTokensServerCapabilities, WorkDoneProgressOptions};

use crate::{abstract_type::DomainType, dev_aid::lsp::to_position, file_position::Span, flattening::{DomainID, IdentifierType}, linker::{FileData, FileUUID, Linker, NameElem}};
use crate::{abstract_type::DomainType, dev_aid::lsp::to_position, file_position::Span, flattening::{DomainID, IdentifierType}, linker::{FileData, FileUUID, Linker, NameElem}, template::TemplateInputKind};

use super::tree_walk::{self, InModule, LocationInfo};

Expand Down Expand Up @@ -128,6 +128,12 @@ fn walk_name_color(file : &FileData, linker : &Linker) -> Vec<(Span, IDEIdentifi
}
LocationInfo::InModule(_md_id, _, _, InModule::Temporary(_)) => {return}
LocationInfo::Type(_, _) => {return}
LocationInfo::TemplateInput(_id, _link_info, _, template_arg) => {
match &template_arg.kind {
TemplateInputKind::Type { .. } => IDEIdentifierType::Type,
TemplateInputKind::Generative { .. } => IDEIdentifierType::Generative,
}
}
LocationInfo::Global(g) => {
match g {
NameElem::Module(_) => IDEIdentifierType::Interface,
Expand Down
74 changes: 61 additions & 13 deletions src/dev_aid/lsp/tree_walk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,20 @@
use std::ops::Deref;

use crate::{
file_position::Span, flattening::{Declaration, DomainID, FlatID, Instruction, Interface, Module, ModuleInterfaceReference, PortID, SubModuleInstance, WireInstance, WireReference, WireReferenceRoot, WireSource, WrittenType}, linker::{FileData, FileUUID, LinkInfo, Linker, ModuleUUID, NameElem}
file_position::Span, flattening::{Declaration, DeclarationPortInfo, DomainID, FlatID, Instruction, Interface, Module, ModuleInterfaceReference, PortID, SubModuleInstance, WireInstance, WireReference, WireReferenceRoot, WireSource, WrittenType}, linker::{FileData, FileUUID, LinkInfo, Linker, ModuleUUID, NameElem}, template::{GlobalReference, TemplateArgKind, TemplateID, TemplateInput, TemplateInputKind}
};

#[derive(Clone, Copy, Debug)]
pub enum InModule<'linker> {
NamedLocal(&'linker Declaration),
NamedSubmodule(&'linker SubModuleInstance),
Temporary(&'linker WireInstance),
Temporary(&'linker WireInstance)
}

#[derive(Clone, Copy, Debug)]
pub enum LocationInfo<'linker> {
InModule(ModuleUUID, &'linker Module, FlatID, InModule<'linker>),
TemplateInput(NameElem, &'linker LinkInfo, TemplateID, &'linker TemplateInput),
Type(&'linker WrittenType, &'linker LinkInfo),
Global(NameElem),
/// The contained module only refers to the module on which the port is defined
Expand All @@ -29,7 +30,8 @@ pub struct RefersTo {
pub local : Option<(ModuleUUID, FlatID)>,
pub global : Option<NameElem>,
pub port : Option<(ModuleUUID, PortID)>,
pub interface : Option<(ModuleUUID, DomainID)>
pub interface : Option<(ModuleUUID, DomainID)>,
pub template_input : Option<(NameElem, TemplateID)>
}

impl<'linker> From<LocationInfo<'linker>> for RefersTo {
Expand All @@ -39,13 +41,21 @@ impl<'linker> From<LocationInfo<'linker>> for RefersTo {
global: None,
port: None,
interface : None,
template_input : None
};
match info {
LocationInfo::InModule(md_id, md, flat_id, flat_obj) => {
match flat_obj {
InModule::NamedLocal(_) => {
if let Some(port_id) = md.ports.find(|_, port| port.declaration_instruction == flat_id) {
result.port = Some((md_id, port_id));
let decl = md.instructions[flat_id].unwrap_wire_declaration();
match decl.is_port {
DeclarationPortInfo::NotPort => {}
DeclarationPortInfo::RegularPort { is_input:_, port_id } => {
result.port = Some((md_id, port_id));
}
DeclarationPortInfo::GenerativeInput(template_id) => {
result.template_input = Some((NameElem::Module(md_id), template_id))
}
}
result.local = Some((md_id, flat_id));
},
Expand All @@ -56,6 +66,16 @@ impl<'linker> From<LocationInfo<'linker>> for RefersTo {
}
}
LocationInfo::Type(_, _) => {}
LocationInfo::TemplateInput(obj, _link_info, template_id, template_arg) => {
match &template_arg.kind {
TemplateInputKind::Type { default_value:_ } => {}
TemplateInputKind::Generative { decl_span:_, declaration_instruction } => {
let NameElem::Module(md_id) = obj else {unreachable!()}; // TODO, local names in types?
result.local = Some((md_id, *declaration_instruction));
}
}
result.template_input = Some((obj, template_id))
}
LocationInfo::Global(name_elem) => {
result.global = Some(name_elem);
}
Expand All @@ -75,14 +95,15 @@ impl RefersTo {
pub fn refers_to_same_as(&self, info : LocationInfo) -> bool {
match info {
LocationInfo::InModule(md_id, _, obj, _) => self.local == Some((md_id, obj)),
LocationInfo::TemplateInput(parent, _, template_id, _) => self.template_input == Some((parent, template_id)),
LocationInfo::Type(_, _) => false,
LocationInfo::Global(ne) => self.global == Some(ne),
LocationInfo::Port(sm, _, p_id) => self.port == Some((sm.module_ref.id, p_id)),
LocationInfo::Interface(md_id, _, i_id, _) => self.interface == Some((md_id, i_id))
}
}
pub fn is_global(&self) -> bool {
self.global.is_some() | self.port.is_some() | self.interface.is_some()
self.global.is_some() | self.port.is_some() | self.interface.is_some() | self.template_input.is_some()
}
}

Expand Down Expand Up @@ -148,6 +169,23 @@ impl<'linker, Visitor : FnMut(Span, LocationInfo<'linker>), Pruner : Fn(Span) ->
}
}

fn walk_global_reference<ID : Copy>(&mut self, parent : NameElem, link_info : &'linker LinkInfo, global : &'linker GlobalReference<ID>) where NameElem : From<ID> {
let target_name_elem = NameElem::from(global.id);
self.visit(global.span, LocationInfo::Global(target_name_elem));
for (id, template_arg) in global.template_args.iter_valids() {
if let Some(name_span) = template_arg.name_specification {
let target_link_info = self.linker.get_link_info(target_name_elem).unwrap();
self.visit(name_span, LocationInfo::TemplateInput(target_name_elem, target_link_info, id, &target_link_info.template_arguments[id]));
}
match &template_arg.kind {
TemplateArgKind::Type(typ_expr) => {
self.walk_type(parent, link_info, typ_expr);
}
TemplateArgKind::Value(_) => {} // Covered by FlatIDs
}
}
}

fn walk_wire_ref(&mut self, md_id : ModuleUUID, md : &'linker Module, wire_ref : &'linker WireReference) {
match &wire_ref.root {
WireReferenceRoot::LocalDecl(decl_id, span) => {
Expand All @@ -171,22 +209,22 @@ impl<'linker, Visitor : FnMut(Span, LocationInfo<'linker>), Pruner : Fn(Span) ->
}
}

fn walk_type(&mut self, typ_expr : &'linker WrittenType, link_info : &'linker LinkInfo) {
fn walk_type(&mut self, parent : NameElem, link_info : &'linker LinkInfo, typ_expr : &'linker WrittenType) {
let typ_expr_span = typ_expr.get_span();
if !(self.should_prune)(typ_expr_span) {
(self.visitor)(typ_expr_span, LocationInfo::Type(typ_expr, link_info));
match typ_expr {
WrittenType::Error(_) => {}
WrittenType::Template(span, link_info) => {
// TODO
WrittenType::Template(span, template_id) => {
self.visit(*span, LocationInfo::TemplateInput(parent, link_info, *template_id, &link_info.template_arguments[*template_id]));
}
WrittenType::Named(named_type) => {
self.visit(named_type.span, LocationInfo::Global(NameElem::Type(named_type.id)));
self.walk_global_reference(parent, link_info, named_type);
}
WrittenType::Array(_, arr_box) => {
let (arr_content_typ, _size_id, _br_span) = arr_box.deref();

self.walk_type(arr_content_typ, link_info)
self.walk_type(parent, link_info, arr_content_typ);
}
}
}
Expand All @@ -210,6 +248,16 @@ impl<'linker, Visitor : FnMut(Span, LocationInfo<'linker>), Pruner : Fn(Span) ->
if !(self.should_prune)(md.link_info.span) {
self.visit(md.link_info.name_span, LocationInfo::Global(NameElem::Module(md_id)));

for (template_id, template_arg) in &md.link_info.template_arguments {
if let TemplateInputKind::Type{default_value} = &template_arg.kind {
self.visit(template_arg.name_span, LocationInfo::TemplateInput(NameElem::Module(md_id), &md.link_info, template_id, template_arg));

if let Some(default_val) = default_value {
self.walk_type(NameElem::Module(md_id), &md.link_info, default_val)
}
}
}

let mut interface_iter = md.interfaces.iter();
// Skip main interface
interface_iter.next();
Expand All @@ -220,13 +268,13 @@ impl<'linker, Visitor : FnMut(Span, LocationInfo<'linker>), Pruner : Fn(Span) ->
for (id, inst) in &md.instructions {
match inst {
Instruction::SubModule(sm) => {
self.visit(sm.module_ref.span, LocationInfo::Global(NameElem::Module(sm.module_ref.id)));
self.walk_global_reference(NameElem::Module(md_id), &md.link_info, &sm.module_ref);
if let Some((_sm_name, sm_name_span)) = &sm.name {
self.visit(*sm_name_span, LocationInfo::InModule(md_id, md, id, InModule::NamedSubmodule(sm)));
}
}
Instruction::Declaration(decl) => {
self.walk_type(&decl.typ_expr, &md.link_info);
self.walk_type(NameElem::Module(md_id), &md.link_info, &decl.typ_expr);
if decl.declaration_itself_is_not_written_to {
self.visit(decl.name_span, LocationInfo::InModule(md_id, md, id, InModule::NamedLocal(decl)));
}
Expand Down
Loading

0 comments on commit 2c9649f

Please sign in to comment.