Skip to content

Commit

Permalink
Show last generative value in hover
Browse files Browse the repository at this point in the history
  • Loading branch information
VonTum committed Feb 7, 2024
1 parent a79880d commit 8bcf918
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 92 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ The main goals of the language are roughly listed below:
- [x] Can Parse Blur2 filter
- [x] If Statements
- [x] Latency Specifiers
- [ ] Array Slices
- [ ] Bound Specifiers
- [ ] Structs
- [x] For Loops
Expand All @@ -74,6 +75,7 @@ The main goals of the language are roughly listed below:
- [x] Net-positive latency cycles error
- [x] Disjoint nodes error
- [x] Indeterminable port latency
- [ ] Latency for output-only modules
- [ ] Integrate into Verilog generation
- [ ] Negative Registers
- [ ] Latency Cuts
Expand Down
31 changes: 21 additions & 10 deletions multiply_add.sus
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,20 @@ module dwiogo : bool[512] data -> bool[256] out {



timeline (v -> v) .. (/ -> v) .. (/ -> v) .. (/ -> v)
module packer : T[256] data /* v _ _ _ */ -> T[64] out { /* v v v v */
state bool[256] save = data[256:511];
out = data[0:255];
#
out = save;
timeline (v, true -> v) .. (/, false -> v) .. (/, false -> v) .. (/, false -> v)
module packer : bool[256] data /* v _ _ _ */, bool valid -> bool[64] o { /* v v v v */
state bool[192] save = data[64:256];
state int part;
initial part = 3;
if valid {
part = 0;
o = data[0:64];
} else {
o = save[part*64 - 64:part*64];
if part < 3 {
part = part + 1;
}
}
}


Expand Down Expand Up @@ -210,13 +218,16 @@ module multiply_add :
reg total = tmp + c;
}

module fibonnaci : -> int num {
module fibonnaci : bool next -> int num {
state int current = 1;
state int current_prev = 0;

num = current + current_prev;
current_prev = current;
current = num;
if next {
num = current + current_prev;
current_prev = current;
current = num;
reg int delay_current = current;
}
}

//timeline (v, true -> /) .. (v, false -> v)*
Expand Down
18 changes: 18 additions & 0 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,24 @@ pub enum IdentifierType {
Generative
}

impl IdentifierType {
pub fn get_keyword(&self) -> &'static str {
match self {
IdentifierType::Input => "input",
IdentifierType::Output => "output",
IdentifierType::Local => "",
IdentifierType::State => "state",
IdentifierType::Generative => "gen",
}
}
pub fn is_generative(&self) -> bool {
*self == IdentifierType::Generative
}
pub fn is_port(&self) -> bool {
*self == IdentifierType::Input || *self == IdentifierType::Output
}
}

#[derive(Debug, Clone, Copy)]
pub enum LocalOrGlobal {
Local(DeclID),
Expand Down
29 changes: 5 additions & 24 deletions src/codegen_fallback.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{iter::zip, ops::Deref};

use crate::{ast::{Module, IdentifierType}, instantiation::{ConnectToPathElem, InstantiatedModule, RealWireDataSource}, linker::{get_builtin_type, TypeUUID}, typing::ConcreteType, tokenizer::get_token_type_name, flattening::Instruction, value::Value};
use crate::{ast::Module, instantiation::{ConnectToPathElem, InstantiatedModule, RealWireDataSource}, linker::{get_builtin_type, TypeUUID}, typing::ConcreteType, tokenizer::get_token_type_name, flattening::Instruction};

fn get_type_name_size(id : TypeUUID) -> u64 {
if id == get_builtin_type("int") {
Expand Down Expand Up @@ -34,24 +34,6 @@ fn typ_to_verilog_array(typ : &ConcreteType) -> String {
}
}

pub fn value_to_str(value : &Value) -> String {
match value {
Value::Bool(b) => if *b {"1'b1"} else {"1'b0"}.to_owned(),
Value::Integer(v) => v.to_string(),
Value::Array(arr_box) => {
let mut result = "[".to_owned();
for v in arr_box.iter() {
result.push_str(&value_to_str(v));
result.push_str(", ");
}
result.push(']');
result
}
Value::Unset => "Value::Unset".to_owned(),
Value::Error => "Value::Error".to_owned(),
}
}

pub fn write_path_to_string(instance : &InstantiatedModule, path : &[ConnectToPathElem]) -> String {
let mut result = String::new();
for path_elem in path {
Expand Down Expand Up @@ -84,9 +66,8 @@ pub fn gen_verilog_code(md : &Module, instance : &InstantiatedModule) -> String
for (_id, w) in &instance.wires {
if let Instruction::Declaration(wire_decl) = &md.flattened.instructions[w.original_wire] {
// Don't print named inputs and outputs, already did that in interface
match wire_decl.identifier_type {
IdentifierType::Input | IdentifierType::Output => {continue;}
IdentifierType::Local | IdentifierType::State | IdentifierType::Generative => {}
if wire_decl.identifier_type.is_port() {
continue;
}
}
let wire_or_reg = if let RealWireDataSource::Multiplexer{is_state, sources: _} = &w.source {
Expand Down Expand Up @@ -117,7 +98,7 @@ pub fn gen_verilog_code(md : &Module, instance : &InstantiatedModule) -> String
program_text.push_str(&format!(" = {}[{arr_idx}];\n", instance.wires[*arr].name));
}
RealWireDataSource::Constant { value } => {
program_text.push_str(&format!(" = {};\n", value_to_str(value)));
program_text.push_str(&format!(" = {};\n", value.to_string()));
}
RealWireDataSource::ReadOnly => {
program_text.push_str(";\n");
Expand All @@ -126,7 +107,7 @@ pub fn gen_verilog_code(md : &Module, instance : &InstantiatedModule) -> String
program_text.push_str(";\n");
if let Some(initial_value) = is_state {
if initial_value.is_valid() {
let initial_value_str = value_to_str(initial_value);
let initial_value_str = initial_value.to_string();
program_text.push_str(&format!("initial {wire_name} = {initial_value_str};\n"));
}
}
Expand Down
58 changes: 35 additions & 23 deletions src/dev_aid/lsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use lsp_server::{Connection, Message, Response};

use lsp_types::notification::Notification;

use crate::{arena_alloc::ArenaVector, ast::{IdentifierType, Span}, dev_aid::syntax_highlighting::create_token_ide_info, errors::{CompileError, ErrorCollector, ErrorLevel}, flattening::{WireInstance, WireSource}, linker::{FileData, FileUUID, FileUUIDMarker, Linker, LocationInfo}, parser::perform_full_semantic_parse, tokenizer::{CharLine, TokenizeResult}, typing::Type};
use crate::{arena_alloc::ArenaVector, ast::{IdentifierType, Module, Span}, dev_aid::syntax_highlighting::create_token_ide_info, errors::{CompileError, ErrorCollector, ErrorLevel}, flattening::{FlatID, WireInstance, WireSource}, instantiation::{SubModuleOrWire, LATENCY_UNSET}, linker::{FileData, FileUUID, FileUUIDMarker, Linker, LocationInfo}, parser::perform_full_semantic_parse, tokenizer::{CharLine, TokenizeResult}, typing::Type};

use super::syntax_highlighting::{IDETokenType, IDEIdentifierType, IDEToken};

Expand Down Expand Up @@ -304,6 +304,31 @@ fn initialize_all_files(init_params : &InitializeParams) -> LoadedFileCache {
result
}

fn gather_hover_infos(md: &Module, id: FlatID, is_generative : bool, file_cache: &LoadedFileCache, hover_list: &mut Vec<MarkedString>) {
md.instantiations.for_each_instance(|inst| {
if is_generative {
let value_str = match &inst.generation_state[id] {
SubModuleOrWire::SubModule(_) | SubModuleOrWire::Wire(_) => unreachable!(),
SubModuleOrWire::CompileTimeValue(v) => format!("``` = {}```", v.to_string()),
SubModuleOrWire::Unnasigned => format!("```never assigned to```"),
};
hover_list.push(MarkedString::String(value_str));
} else {
for (_id, wire) in &inst.wires {
if wire.original_wire != id {continue}
let typ_str = wire.typ.to_string(&file_cache.linker.types);
let name_str = &wire.name;
let latency_str = if wire.absolute_latency == LATENCY_UNSET {
format!("{}", wire.absolute_latency)
} else {
"?".to_owned()
};
hover_list.push(MarkedString::String(format!("```{typ_str} {name_str}'{latency_str}```")));
}
}
});
}

fn handle_request(method : &str, params : serde_json::Value, file_cache : &mut LoadedFileCache, debug : bool) -> Result<serde_json::Value, serde_json::Error> {
match method {
request::HoverRequest::METHOD => {
Expand All @@ -321,31 +346,18 @@ fn handle_request(method : &str, params : serde_json::Value, file_cache : &mut L
let decl = md.flattened.instructions[decl_id].extract_wire_declaration();
let typ_str = decl.typ.to_string(&file_cache.linker.types);
let name_str = &decl.name;
hover_list.push(MarkedString::String(format!("{typ_str} {name_str}")));

md.instantiations.for_each_instance(|inst| {
for (_id, wire) in &inst.wires {
if wire.original_wire != decl_id {continue}
let typ_str = wire.typ.to_string(&file_cache.linker.types);
let name_str = &wire.name;
let latency = wire.absolute_latency;
hover_list.push(MarkedString::String(format!("{typ_str} {name_str}'{latency}")));
}
});

let identifier_type_keyword = decl.identifier_type.get_keyword();
hover_list.push(MarkedString::String(format!("{identifier_type_keyword} {typ_str} {name_str}")));

gather_hover_infos(md, decl_id, decl.identifier_type.is_generative(), file_cache, &mut hover_list);
}
LocationInfo::Temporary(md, id, wire) => {
let typ_str = wire.typ.to_string(&file_cache.linker.types);

hover_list.push(MarkedString::String(format!("{typ_str}")));
md.instantiations.for_each_instance(|inst| {
for (_id, wire) in &inst.wires {
if wire.original_wire != id {continue}
let typ_str = wire.typ.to_string(&file_cache.linker.types);
let name_str = &wire.name;
let latency = wire.absolute_latency;
hover_list.push(MarkedString::String(format!("{typ_str} {name_str}'{latency}")));
}
});
let gen_kw = if wire.is_compiletime {"gen "} else {""};
hover_list.push(MarkedString::String(format!("{gen_kw}{typ_str}")));
gather_hover_infos(md, id, wire.is_compiletime, file_cache, &mut hover_list);
}
LocationInfo::Type(typ) => {
hover_list.push(MarkedString::String(typ.to_type().to_string(&file_cache.linker.types)));
Expand Down Expand Up @@ -423,7 +435,7 @@ fn handle_notification(connection: &Connection, notification : lsp_server::Notif
notification::DidChangeWatchedFiles::METHOD => {
println!("Workspace Files modified");
*file_cache = initialize_all_files(initialize_params);

push_all_errors(&connection, &file_cache)?;
}
other => {
Expand Down
6 changes: 3 additions & 3 deletions src/flattening.rs
Original file line number Diff line number Diff line change
Expand Up @@ -648,7 +648,7 @@ impl<'inst, 'l, 'm> FlatteningContext<'inst, 'l, 'm> {
match &self.instructions[inst_id] {
Instruction::SubModule(_) => {}
Instruction::Declaration(decl) => {
if decl.identifier_type == IdentifierType::Generative {
if decl.identifier_type.is_generative() {
assert!(declaration_depths[inst_id].is_none());
declaration_depths[inst_id] = Some(runtime_if_stack.len())
}
Expand All @@ -665,7 +665,7 @@ impl<'inst, 'l, 'm> FlatteningContext<'inst, 'l, 'm> {
let mut is_generative = true;
if let WireSource::WireRead(from) = &wire.source {
let decl = self.instructions[*from].extract_wire_declaration();
if decl.identifier_type != IdentifierType::Generative {
if !decl.identifier_type.is_generative() {
is_generative = false;
}
} else {
Expand All @@ -684,7 +684,7 @@ impl<'inst, 'l, 'm> FlatteningContext<'inst, 'l, 'm> {
let from_wire = self.instructions[conn.from].extract_wire();
match conn.write_type {
WriteType::Connection{num_regs : _, regs_span : _} => {
if decl.identifier_type == IdentifierType::Generative {
if decl.identifier_type.is_generative() {
// Check that whatever's written to this declaration is also generative
self.must_be_compiletime_with_info(from_wire, "Assignments to generative variables", || vec![decl.make_declared_here(self.errors.file)]);

Expand Down
52 changes: 30 additions & 22 deletions src/instantiation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,12 @@ pub struct InstantiatedModule {
pub name : Box<str>, // Unique name involving all template arguments
pub interface : InterfacePorts<WireID>, // Interface is only valid if all wires of the interface were valid
pub wires : FlatAlloc<RealWire, WireIDMarker>,
pub submodules : FlatAlloc<SubModule, SubModuleIDMarker>
pub submodules : FlatAlloc<SubModule, SubModuleIDMarker>,
pub generation_state : FlatAlloc<SubModuleOrWire, FlatIDMarker>
}

#[derive(Debug,Clone)]
enum SubModuleOrWire {
pub enum SubModuleOrWire {
SubModule(SubModuleID),
Wire(WireID),
CompileTimeValue(Value),
Expand All @@ -117,12 +118,12 @@ enum SubModuleOrWire {

impl SubModuleOrWire {
#[track_caller]
fn extract_wire(&self) -> WireID {
pub fn extract_wire(&self) -> WireID {
let Self::Wire(result) = self else {panic!("Failed wire extraction! Is {self:?} instead")};
*result
}
#[track_caller]
fn extract_generation_value(&self) -> &Value {
pub fn extract_generation_value(&self) -> &Value {
let Self::CompileTimeValue(result) = self else {panic!("Failed GenerationValue extraction! Is {self:?} instead")};
result
}
Expand Down Expand Up @@ -404,7 +405,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> {
}
Instruction::Declaration(wire_decl) => {
let typ = self.concretize_type(&wire_decl.typ, wire_decl.typ_expr.get_span())?;
if wire_decl.identifier_type == IdentifierType::Generative {
if wire_decl.identifier_type.is_generative() {
/*Do nothing (in fact re-initializes the wire to 'empty'), just corresponds to wire declaration*/
/*if wire_decl.read_only { // Don't know why this check is *here*
todo!("Modules can't be computed at compile time yet");
Expand Down Expand Up @@ -627,7 +628,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> {

#[derive(Debug)]
pub struct InstantiationList {
cache : RefCell<Vec<(Option<Rc<InstantiatedModule>>, ErrorCollector)>>
cache : RefCell<Vec<(Rc<InstantiatedModule>, ErrorCollector)>>
}

impl InstantiationList {
Expand All @@ -650,24 +651,31 @@ impl InstantiationList {
errors : ErrorCollector::new(flattened.errors.file)
};

if let Some(interface) = context.instantiate_full() {
let result = Some(Rc::new(InstantiatedModule{
name : name.to_owned().into_boxed_str(),
wires : context.wires,
submodules : context.submodules,
interface,
}));
let interface = context.instantiate_full();
let result = Rc::new(InstantiatedModule{
name : name.to_owned().into_boxed_str(),
wires : context.wires,
submodules : context.submodules,
interface : interface.unwrap_or(InterfacePorts::empty()), // Empty value. Invalid interface can't get accessed from result of this method, as that should have produced an error
generation_state : context.generation_state
});

cache_borrow.push((result.clone(), context.errors));
return result;
} else {
cache_borrow.push((None, context.errors));
if context.errors.did_error.get() {
cache_borrow.push((result, context.errors));
return None;
};
} else {
cache_borrow.push((result.clone(), context.errors));
return Some(result);
}
}

let instance_id = 0; // Temporary, will always be 0 while not template arguments
cache_borrow[instance_id].0.clone()
let instance = &cache_borrow[instance_id];
if instance.1.did_error.get() {
Some(instance.0.clone())
} else {
None
}
}

pub fn collect_errors(&self, errors : &ErrorCollector) {
Expand All @@ -681,12 +689,12 @@ impl InstantiationList {
self.cache.borrow_mut().clear()
}

// Also passes over invalid instances. Instance validity should not be assumed!
// Only used for things like syntax highlighting
pub fn for_each_instance<F : FnMut(&InstantiatedModule)>(&self, mut f : F) {
let borrow = self.cache.borrow();
for v in borrow.iter() {
if let Some(vv) = &v.0 {
f(vv.as_ref())
}
f(v.0.as_ref())
}
}
}
2 changes: 1 addition & 1 deletion src/linker.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{collections::{HashMap, HashSet}, rc::Rc, cell::RefCell};

use crate::{arena_alloc::{ArenaAllocator, UUIDMarker, UUID}, ast::{LinkInfo, Module, Span}, errors::{error_info, ErrorCollector}, flattening::{ConnectionWrite, FlatID, FlattenedModule, Instruction, WireInstance, WireSource}, instantiation::InstantiatedModule, parser::{FullParseResult, TokenTreeNode}, tokenizer::TokenizeResult, typing::{Type, WrittenType}, util::{const_str_position, const_str_position_in_tuples}, value::Value};
use crate::{arena_alloc::{ArenaAllocator, UUIDMarker, UUID}, ast::{LinkInfo, Module, Span}, errors::{error_info, ErrorCollector}, flattening::{FlatID, FlattenedModule, Instruction, WireInstance, WireSource}, instantiation::InstantiatedModule, parser::{FullParseResult, TokenTreeNode}, tokenizer::TokenizeResult, typing::{Type, WrittenType}, util::{const_str_position, const_str_position_in_tuples}, value::Value};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ModuleUUIDMarker;
Expand Down
Loading

0 comments on commit 8bcf918

Please sign in to comment.