Skip to content

Commit

Permalink
Unified LSP queries over a single tree walker. Fixed a bunch of submo…
Browse files Browse the repository at this point in the history
…dule-related rendering issues
  • Loading branch information
VonTum committed May 12, 2024
1 parent 4909bce commit 0de4dc7
Show file tree
Hide file tree
Showing 13 changed files with 343 additions and 348 deletions.
5 changes: 3 additions & 2 deletions multiply_add.sus
Original file line number Diff line number Diff line change
Expand Up @@ -682,15 +682,16 @@ module monotonize_down : bool[16] mbf -> bool[16] mtDown {
}
}


// Main module documentation
module submodule_named_ports : int port_a, int port_b -> int port_c {
port_c = port_a + port_b
}

module use_submodule_named_ports : int i -> int o {
// Test submodule documentation
submodule_named_ports sm

o = sm(i, i)
//o = sm(i, i)

sm.port_a = i

Expand Down
248 changes: 85 additions & 163 deletions src/dev_aid/lsp.rs

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/dev_aid/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@

pub mod syntax_highlighting;

pub mod tree_walk;

#[cfg(feature = "lsp")]
pub mod lsp;
70 changes: 1 addition & 69 deletions src/dev_aid/syntax_highlighting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,79 +2,11 @@
use std::{ops::Range, path::PathBuf};

use crate::{
arena_alloc::ArenaVector, compiler_top::{add_file, recompile_all}, config::config, errors::{CompileError, ErrorLevel}, file_position::Span, flattening::{IdentifierType, Instruction, Module, WireReference, WireReferenceRoot, WireSource}, linker::{FileUUID, FileUUIDMarker, Linker, NameElem}
arena_alloc::ArenaVector, compiler_top::{add_file, recompile_all}, config::config, errors::{CompileError, ErrorLevel}, linker::{FileUUID, FileUUIDMarker, Linker}
};

use ariadne::*;

#[derive(Debug,Clone,Copy,PartialEq,Eq)]
pub enum IDEIdentifierType {
Value(IdentifierType),
Type,
Interface,
Constant
}

pub fn walk_name_color_wireref(module : &Module, wire_ref : &WireReference, result : &mut Vec<(IDEIdentifierType, Span)>) {
match &wire_ref.root {
WireReferenceRoot::LocalDecl(decl_id, span) => {
let decl = module.instructions[*decl_id].unwrap_wire_declaration();
result.push((IDEIdentifierType::Value(decl.identifier_type), *span));
}
WireReferenceRoot::NamedConstant(_cst, span) => {
result.push((IDEIdentifierType::Constant, *span));
}
WireReferenceRoot::SubModulePort(port) => {
if let Some(span) = port.port_name_span {
result.push((IDEIdentifierType::Value(port.port_identifier_typ), span))
}
}
}
}

pub fn walk_name_color(all_objects : &[NameElem], linker : &Linker) -> Vec<(IDEIdentifierType, Span)> {
let mut result : Vec<(IDEIdentifierType, Span)> = Vec::new();
for obj_uuid in all_objects {
let (ide_typ, link_info) = match obj_uuid {
NameElem::Module(id) => {
let module = &linker.modules[*id];
for (_id, item) in &module.instructions {
match item {
Instruction::Wire(w) => {
match &w.source {
WireSource::WireRead(from_wire) => {
walk_name_color_wireref(module, from_wire, &mut result);
}
WireSource::UnaryOp { op:_, right:_ } => {}
WireSource::BinaryOp { op:_, left:_, right:_ } => {}
WireSource::Constant(_) => {}
}
}
Instruction::Declaration(decl) => {
decl.typ_expr.for_each_located_type(&mut |_, span| {
result.push((IDEIdentifierType::Type, span));
});
result.push((IDEIdentifierType::Value(decl.identifier_type), decl.name_span));
}
Instruction::Write(conn) => {
walk_name_color_wireref(module, &conn.to, &mut result);
}
Instruction::SubModule(sm) => {
result.push((IDEIdentifierType::Interface, sm.module_name_span));
}
Instruction::IfStatement(_) | Instruction::ForStatement(_) => {}
}
}
(IDEIdentifierType::Interface, &module.link_info)
}
_other => {todo!("Name Color for non-modules not implemented")}
};

result.push((ide_typ, link_info.name_span));
}
result
}

pub fn compile_all(file_paths : Vec<PathBuf>) -> (Linker, ArenaVector<(PathBuf, Source), FileUUIDMarker>) {
let mut linker = Linker::new();
let mut paths_arena : ArenaVector<(PathBuf, Source), FileUUIDMarker> = ArenaVector::new();
Expand Down
157 changes: 157 additions & 0 deletions src/dev_aid/tree_walk.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@

use std::ops::Deref;

use crate::{
file_position::Span, flattening::{Declaration, FlatID, Instruction, Module, Port, PortID, SubModuleInstance, WireInstance, WireReference, WireReferenceRoot, WireSource}, linker::{FileData, Linker, ModuleUUID, NameElem}, typing::WrittenType
};

#[derive(Clone, Copy, Debug)]
pub enum LocationInfo<'linker> {
NamedLocal(&'linker Module, FlatID, &'linker Declaration),
NamedSubmodule(&'linker Module, FlatID, &'linker SubModuleInstance),
Temporary(&'linker Module, FlatID, &'linker WireInstance),
Type(&'linker WrittenType),
Global(NameElem),
Port(PortID, ModuleUUID, &'linker Port)
}

/// Walks the file, and provides all [LocationInfo]s.
pub fn visit_all<'linker, Visitor : FnMut(Span, LocationInfo<'linker>)>(linker : &'linker Linker, file : &'linker FileData, visitor : Visitor) {
let mut walker = TreeWalker {
linker,
visitor,
should_prune: |_| false,
};

walker.walk_file(file);
}

/// Walks the file, and finds the [LocationInfo] that is the most relevant
///
/// IE, the [LocationInfo] in the selection area that has the smallest span.
pub fn get_selected<'linker>(linker : &'linker Linker, file : &'linker FileData, position : usize) -> Option<(Span, LocationInfo<'linker>)> {
let mut best_object : Option<LocationInfo<'linker>> = None;
let mut best_span : Span = Span::MAX_POSSIBLE_SPAN;

let mut walker = TreeWalker {
linker,
visitor : |span, info| {
if span.size() <= best_span.size() {
//assert!(span.size() < self.best_span.size());
// May not be the case. Do prioritize later ones, as they tend to be nested
best_span = span;
best_object = Some(info);
}
},
should_prune: |span| !span.contains_pos(position),
};

walker.walk_file(file);

best_object.map(|v| (best_span, v))
}


struct TreeWalker<'linker, Visitor : FnMut(Span, LocationInfo<'linker>), Pruner : Fn(Span) -> bool> {
linker : &'linker Linker,
visitor : Visitor,
should_prune : Pruner
}

impl<'linker, Visitor : FnMut(Span, LocationInfo<'linker>), Pruner : Fn(Span) -> bool> TreeWalker<'linker, Visitor, Pruner> {
fn visit(&mut self, span : Span, info : LocationInfo<'linker>) {
if !(self.should_prune)(span) {
(self.visitor)(span, info);
}
}

fn walk_wire_ref(&mut self, md : &'linker Module, wire_ref : &'linker WireReference) {
match &wire_ref.root {
WireReferenceRoot::LocalDecl(decl_id, span) => {
self.visit(*span, LocationInfo::NamedLocal(md, *decl_id, md.instructions[*decl_id].unwrap_wire_declaration()));
}
WireReferenceRoot::NamedConstant(cst, span) => {
self.visit(*span, LocationInfo::Global(NameElem::Constant(*cst)))
}
WireReferenceRoot::SubModulePort(port) => {
if let Some(submod_name_span) = port.submodule_name_span {
self.visit(submod_name_span, LocationInfo::NamedSubmodule(md, port.submodule_flat, md.instructions[port.submodule_flat].unwrap_submodule()));
}
if let Some(span) = port.port_name_span {
let module_uuid = md.instructions[port.submodule_flat].unwrap_submodule().module_uuid;
let submodule = &self.linker.modules[module_uuid];
self.visit(span, LocationInfo::Port(port.port, module_uuid, &submodule.module_ports.ports[port.port]))
}
}
}
}

fn walk_type(&mut self, 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));
match typ_expr {
WrittenType::Error(_) => {}
WrittenType::Named(span, name_id) => {
self.visit(*span, LocationInfo::Global(NameElem::Type(*name_id)));
}
WrittenType::Array(_, arr_box) => {
let (arr_content_typ, _size_id, _br_span) = arr_box.deref();

self.walk_type(arr_content_typ)
}
}
}
}

fn walk_module(&mut self, md : &'linker Module) {
for (id, inst) in &md.instructions {
match inst {
Instruction::SubModule(sm) => {
self.visit(sm.module_name_span, LocationInfo::Global(NameElem::Module(sm.module_uuid)));
if let Some((_sm_name, sm_name_span)) = &sm.name {
self.visit(*sm_name_span, LocationInfo::NamedSubmodule(md, id, sm));
}
}
Instruction::Declaration(decl) => {
self.walk_type(&decl.typ_expr);
if decl.declaration_itself_is_not_written_to {
self.visit(decl.name_span, LocationInfo::NamedLocal(md, id, decl));
}
}
Instruction::Wire(wire) => {
if let WireSource::WireRef(wire_ref) = &wire.source {
self.walk_wire_ref(md, wire_ref);
} else {
self.visit(wire.span, LocationInfo::Temporary(md, id, wire));
};
}
Instruction::Write(write) => {
self.walk_wire_ref(md, &write.to);
}
Instruction::IfStatement(_) | Instruction::ForStatement(_) => {}
};
}
}

fn walk_file(&mut self, file : &'linker FileData) {
for global in &file.associated_values {
match *global {
NameElem::Module(md_id) => {
let md = &self.linker.modules[md_id];

if !(self.should_prune)(md.link_info.span) {
self.visit(md.link_info.name_span, LocationInfo::Global(NameElem::Module(md_id)));
self.walk_module(md);
}
}
NameElem::Type(_) => {
todo!()
}
NameElem::Constant(_) => {
todo!()
}
}
}
}
}
6 changes: 0 additions & 6 deletions src/file_position.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ impl Display for Span {
#[derive(Clone,Copy,Debug,PartialEq,Eq,Hash)]
pub struct BracketSpan(Span);

#[allow(dead_code)]
impl BracketSpan {
pub fn from_outer(span : Span) -> Self {Self(span.debug())}
pub fn inner_span(&self) -> Span {
Expand Down Expand Up @@ -169,11 +168,6 @@ impl FileText {
self.byte_to_linecol(span.0)..self.byte_to_linecol(span.1)
}

#[allow(dead_code)]
pub fn whole_file_span(&self) -> Span {
Span(0, self.file_text.len()).debug()
}

pub fn is_span_valid(&self, span : Span) -> bool {
span.debug();
span.1 <= self.file_text.len()
Expand Down
42 changes: 2 additions & 40 deletions src/flattening/initialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,11 @@ use sus_proc_macro::{field, kind};


use crate::{
arena_alloc::{FlatAlloc, UUID}, errors::ErrorCollector, file_position::{FileText, Span}, flattening::Module, instantiation::InstantiationList, linker::{checkpoint::CheckPoint, FileBuilder, LinkInfo, ResolvedGlobals}, parser::Cursor
arena_alloc::{FlatAlloc, UUID}, errors::ErrorCollector, file_position::FileText, flattening::Module, instantiation::InstantiationList, linker::{checkpoint::CheckPoint, FileBuilder, LinkInfo, ResolvedGlobals}, parser::Cursor
};

use super::*;

#[derive(Debug)]
pub struct Port {
pub name : String,
pub name_span : Span,
pub decl_span : Span,
pub id_typ : IdentifierType,
pub interface : InterfaceID,
/// This is only set after flattening is done. Initially just [UUID::PLACEHOLDER]
pub declaration_instruction : FlatID
}

#[derive(Debug)]
pub struct Interface {
pub ports_for_this_interface : PortIDRange,
pub func_call_inputs : PortIDRange,
pub func_call_outputs : PortIDRange
}

#[derive(Debug)]
pub struct ModulePorts {
pub ports : FlatAlloc<Port, PortIDMarker>,
pub interfaces : FlatAlloc<Interface, InterfaceIDMarker>
}

impl ModulePorts {
pub const MAIN_INTERFACE_ID : InterfaceID = InterfaceID::from_hidden_value(0);

/// This function is intended to retrieve a known port while walking the syntax tree. panics if the port doesn't exist
pub fn get_port_by_decl_span(&self, span : Span) -> PortID {
for (id, data) in &self.ports {
if data.decl_span == span {
return id
}
}
unreachable!()
}
}

pub fn gather_initial_file_data(builder : &mut FileBuilder) {
let mut cursor = Cursor::new_at_root(builder.tree, builder.file_text);
cursor.list_and_report_errors(kind!("source_file"), &builder.other_parsing_errors, |cursor| {
Expand Down Expand Up @@ -120,7 +82,7 @@ fn gather_decl_names_in_list(id_typ: IdentifierType, interface : InterfaceID, po
cursor.field(field!("type"));
let name_span = cursor.field_span(field!("name"), kind!("identifier"));
let name = file_text[name_span].to_owned();
ports.alloc(Port{name, name_span, decl_span, id_typ, interface, declaration_instruction : UUID::PLACEHOLDER})
ports.alloc(Port{name, name_span, decl_span, identifier_type: id_typ, interface, declaration_instruction : UUID::PLACEHOLDER})
});
});
ports.range_since(list_start_at)
Expand Down
Loading

0 comments on commit 0de4dc7

Please sign in to comment.