diff --git a/src/block_vector.rs b/src/block_vector.rs index c0573aa..06c138e 100644 --- a/src/block_vector.rs +++ b/src/block_vector.rs @@ -2,15 +2,13 @@ use std::{cell::{UnsafeCell, Cell}, mem::MaybeUninit, ops::{DerefMut, Deref, Ind -/* - Has the property that appends don't move other elements. References are always preserved, therefore append is const - - Critically, alloc takes a CONST self, because using this will not invalidate any references derived from this - However, IndexMut still requires a mutable reference, since we can edit any arbitrary element, and the compiler can't check for overlap there - - The const iterator exists, though it is not recommended to append elements while iterating over it. The const iterator would continue even onto newer elements - Existence of the mutable iterator disallows updating the container of course -*/ +/// Has the property that appends don't move other elements. References are always preserved, therefore append is const +/// +/// Critically, alloc takes a CONST self, because using this will not invalidate any references derived from this +/// However, IndexMut still requires a mutable reference, since we can edit any arbitrary element, and the compiler can't check for overlap there +/// +/// The const iterator exists, though it is not recommended to append elements while iterating over it. The const iterator would continue even onto newer elements +/// Existence of the mutable iterator disallows updating the container of course #[derive(Default)] pub struct BlockVec { blocks : UnsafeCell; BLOCK_SIZE]>>>, @@ -58,6 +56,8 @@ impl BlockVec { self.length.get() == 0 } + /// Critically, since appending to [BlockVec] is non-mutable, it is possible to do so while holding a [BlockVecIter]. + /// BlockVecIter only iterates up to the size the BlockVec had when [BlockVec::iter] was called pub fn iter<'s>(&'s self) -> BlockVecIter<'s, T, BLOCK_SIZE> { self.into_iter() } diff --git a/src/codegen/system_verilog.rs b/src/codegen/system_verilog.rs index c4ab301..189a796 100644 --- a/src/codegen/system_verilog.rs +++ b/src/codegen/system_verilog.rs @@ -4,7 +4,7 @@ use std::ops::Deref; use crate::linker::{IsExtern, LinkInfo}; use crate::prelude::*; -use crate::flattening::{DeclarationPortInfo, Instruction, Module, Port}; +use crate::flattening::{DeclarationKind, Instruction, Module, Port}; use crate::instantiation::{ InstantiatedModule, RealWire, RealWireDataSource, RealWirePathElem, CALCULATE_LATENCY_LATER, }; @@ -221,7 +221,7 @@ impl<'g, 'out, Stream: std::fmt::Write> CodeGenerationContext<'g, 'out, Stream> &self.md.link_info.instructions[w.original_instruction] { // Don't print named inputs and outputs, already did that in interface - if let DeclarationPortInfo::RegularPort { .. } = wire_decl.is_port { + if let DeclarationKind::RegularPort { .. } = wire_decl.decl_kind { continue; } } @@ -364,9 +364,9 @@ impl<'g, 'out, Stream: std::fmt::Write> CodeGenerationContext<'g, 'out, Stream> for s in sources { let path = self.wire_ref_path_to_string(&s.to_path, w.absolute_latency); - let from_name = self.wire_name(s.from.from, w.absolute_latency); + let from_name = self.wire_name(s.from, w.absolute_latency); self.program_text.write_char('\t').unwrap(); - for cond in s.from.condition.iter() { + for cond in s.condition.iter() { let cond_name = self.wire_name(cond.condition_wire, w.absolute_latency); let invert = if cond.inverse { "!" } else { "" }; write!(self.program_text, "if({invert}{cond_name}) ").unwrap(); diff --git a/src/codegen/vhdl.rs b/src/codegen/vhdl.rs index 29f5626..ccdb8c6 100644 --- a/src/codegen/vhdl.rs +++ b/src/codegen/vhdl.rs @@ -1,6 +1,6 @@ use crate::{ - flattening::{DeclarationPortInfo, Instruction}, linker::IsExtern, typing::concrete_type::ConcreteType, FlatAlloc, InstantiatedModule, Linker, Module, WireIDMarker + flattening::{DeclarationKind, Instruction}, linker::IsExtern, typing::concrete_type::ConcreteType, FlatAlloc, InstantiatedModule, Linker, Module, WireIDMarker }; use std::ops::Deref; use std::fmt::Write; @@ -137,7 +137,7 @@ impl<'g, 'out, Stream: std::fmt::Write> CodeGenerationContext<'g, 'out, Stream> if let Instruction::Declaration(wire_decl) = &self.md.link_info.instructions[wire.original_instruction] { - if let DeclarationPortInfo::RegularPort { .. } = wire_decl.is_port { + if let DeclarationKind::RegularPort { .. } = wire_decl.decl_kind { return false; } } diff --git a/src/config.rs b/src/config.rs index 4bc4c86..ce20e8e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -27,6 +27,7 @@ pub enum TargetLanguage { VHDL, } +/// All command-line flags are converted to this struct, of which the singleton instance can be acquired using [crate::config::config] #[derive(Debug, PartialEq, Eq)] pub struct ConfigStruct { pub use_lsp: bool, @@ -175,6 +176,7 @@ where }) } +/// Access the singleton [ConfigStruct] representing the CLI arguments passed to `sus_compiler` pub fn config() -> &'static ConfigStruct { static CONFIG: LazyLock = LazyLock::new(|| { parse_args(std::env::args_os()) diff --git a/src/dev_aid/lsp/hover_info.rs b/src/dev_aid/lsp/hover_info.rs index aa75635..d5fd520 100644 --- a/src/dev_aid/lsp/hover_info.rs +++ b/src/dev_aid/lsp/hover_info.rs @@ -5,7 +5,7 @@ use crate::to_string::pretty_print_concrete_instance; use lsp_types::{LanguageString, MarkedString}; -use crate::flattening::{DeclarationPortInfo, IdentifierType, InterfaceToDomainMap, Module}; +use crate::flattening::{DeclarationKind, IdentifierType, InterfaceToDomainMap, Module}; use crate::instantiation::{SubModuleOrWire, CALCULATE_LATENCY_LATER}; use crate::linker::{Documentation, FileData, LinkInfo, NameElem}; @@ -108,13 +108,13 @@ pub fn hover(info: LocationInfo, linker: &Linker, file_data: &FileData) -> Vec details_vec.push(if is_input { "input" } else { "output" }), - DeclarationPortInfo::NotPort | DeclarationPortInfo::StructField { field_id:_ } => {} - DeclarationPortInfo::GenerativeInput(_) => details_vec.push("param"), + DeclarationKind::NotPort | DeclarationKind::StructField { field_id:_ } => {} + DeclarationKind::GenerativeInput(_) => details_vec.push("param"), } match decl.identifier_type { @@ -203,7 +203,7 @@ pub fn hover(info: LocationInfo, linker: &Linker, file_data: &FileData) -> Vec { NamedLocal(&'linker Declaration), NamedSubmodule(&'linker SubModuleInstance), - Temporary(&'linker WireInstance), + Temporary(&'linker Expression), } #[derive(Clone, Copy, Debug)] @@ -56,17 +56,17 @@ impl<'linker> From> for RefersTo { match info { LocationInfo::InModule(md_id, md, flat_id, flat_obj) => match flat_obj { InModule::NamedLocal(_) => { - let decl = md.link_info.instructions[flat_id].unwrap_wire_declaration(); - match decl.is_port { - DeclarationPortInfo::NotPort => {} - DeclarationPortInfo::StructField { field_id:_ } => {} - DeclarationPortInfo::RegularPort { + let decl = md.link_info.instructions[flat_id].unwrap_declaration(); + match decl.decl_kind { + DeclarationKind::NotPort => {} + DeclarationKind::StructField { field_id:_ } => {} + DeclarationKind::RegularPort { is_input: _, port_id, } => { result.port = Some((md_id, port_id)); } - DeclarationPortInfo::GenerativeInput(template_id) => { + DeclarationKind::GenerativeInput(template_id) => { result.template_input = Some((NameElem::Module(md_id), template_id)) } } @@ -249,7 +249,7 @@ impl<'linker, Visitor: FnMut(Span, LocationInfo<'linker>), Pruner: Fn(Span) -> b md_id, md, *decl_id, - InModule::NamedLocal(md.link_info.instructions[*decl_id].unwrap_wire_declaration()), + InModule::NamedLocal(md.link_info.instructions[*decl_id].unwrap_declaration()), ), ); } @@ -411,8 +411,8 @@ impl<'linker, Visitor: FnMut(Span, LocationInfo<'linker>), Pruner: Fn(Span) -> b ); } } - Instruction::Wire(wire) => { - if let WireSource::WireRef(wire_ref) = &wire.source { + Instruction::Expression(wire) => { + if let ExpressionSource::WireRef(wire_ref) = &wire.source { self.walk_wire_ref(md_id, md, wire_ref); } else { self.visit( diff --git a/src/errors.rs b/src/errors.rs index 042b013..2026a69 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -13,6 +13,9 @@ pub enum ErrorLevel { Warning, } +/// Represents a comment about a location in the source code. +/// +/// Multiple infos can be attached to a single [CompileError] #[derive(Debug, Clone)] pub struct ErrorInfo { pub position: Span, @@ -20,6 +23,9 @@ pub struct ErrorInfo { pub info: String, } +/// Represents an error or warning that the compiler produced. They can be shown in the IDE, or on the CLI +/// +/// All errors for a single file are stored together, which is why this struct does not contain a FileUUID #[derive(Debug, Clone)] pub struct CompileError { pub position: Span, @@ -30,7 +36,7 @@ pub struct CompileError { /// Stores all errors gathered within a context for reporting to the user. /// -/// Only editable by converting to a ErrorCollector using [ErrorStore::take_for_editing] +/// Only editable by converting to a ErrorCollector using [ErrorCollector::from_storage] #[derive(Debug, Clone)] pub struct ErrorStore { errors: Vec, @@ -184,6 +190,11 @@ impl<'l> Drop for ErrorCollector<'l> { } } +/// Intermediary struct to make adding infos far easier. +/// +/// Use as: +/// +/// errors.warn(span, "Unused Variable").info(span2, file2, "In module").info(blablabla) pub struct ErrorReference<'ec> { err_collector: &'ec ErrorCollector<'ec>, pos: usize, diff --git a/src/file_position.rs b/src/file_position.rs index f5ea7eb..fd94e17 100644 --- a/src/file_position.rs +++ b/src/file_position.rs @@ -5,7 +5,7 @@ use std::{ use crate::prelude::FileUUID; -// Span is defined as byte-byte idx. Start inclusive, end exclusive +/// [Span] is defined as byte-byte idx. Start inclusive, end exclusive #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct Span(usize, usize); @@ -76,6 +76,9 @@ impl Display for Span { } } +/// A span for something that is between brackets. The assumption is that the brackets are 1 byte each. +/// +/// This struct is provided to improve readability on using these spans #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct BracketSpan(Span); diff --git a/src/flattening/flatten.rs b/src/flattening/flatten.rs index cc4ae17..24489d2 100644 --- a/src/flattening/flatten.rs +++ b/src/flattening/flatten.rs @@ -211,6 +211,12 @@ enum DomainAllocOption { NonGenerativeKnown(DomainID) } +#[derive(Debug)] +enum ModuleOrWrittenType { + WrittenType(WrittenType), + Module(GlobalReference), +} + impl TypingAllocator { fn alloc_unset_type(&mut self, domain: DomainAllocOption) -> FullType { FullType { @@ -310,10 +316,10 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { (match self.local_variable_context.get_declaration_for(name) { Some(NamedLocal::TemplateType(t)) => TemplateArgKind::Type(WrittenType::TemplateVariable(name_span, t)), Some(NamedLocal::Declaration(decl_id)) => { - let wire_read_id = self.instructions.alloc(Instruction::Wire(WireInstance { + let wire_read_id = self.instructions.alloc(Instruction::Expression(Expression { typ: self.type_alloc.alloc_unset_type(DomainAllocOption::Generative), span: name_span, - source: WireSource::WireRef(WireReference::simple_var_read(decl_id, true, name_span)) + source: ExpressionSource::WireRef(WireReference::simple_var_read(decl_id, true, name_span)) })); TemplateArgKind::Value(wire_read_id) } @@ -520,7 +526,7 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { match conflict { NamedLocal::Declaration(decl_id) => { err_ref.info_obj_same_file( - self.instructions[decl_id].unwrap_wire_declaration(), + self.instructions[decl_id].unwrap_declaration(), ); } NamedLocal::SubModule(submod_id) => { @@ -574,36 +580,36 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { let declaration_modifiers = cursor.optional_field(field!("declaration_modifiers")).then(|| cursor.kind_span()); // Still gets overwritten - let mut is_port = match declaration_context { + let mut decl_kind = match declaration_context { DeclarationContext::IO{is_input} => { if let Some((_, io_span)) = io_kw { self.errors.error(io_span, "Cannot redeclare 'input' or 'output' on functional syntax IO"); } - DeclarationPortInfo::RegularPort { is_input, port_id: PortID::PLACEHOLDER } + DeclarationKind::RegularPort { is_input, port_id: PortID::PLACEHOLDER } } DeclarationContext::Generative(_) => { if let Some((_, io_span)) = io_kw { self.errors.error(io_span, "Cannot declare 'input' or 'output' to declarations in a generative context"); } - DeclarationPortInfo::NotPort + DeclarationKind::NotPort } DeclarationContext::TemplateGenerative(template_id) => { if let Some((_, io_span)) = io_kw { self.errors.error(io_span, "Cannot declare 'input' or 'output' on template values"); } - DeclarationPortInfo::GenerativeInput(template_id) + DeclarationKind::GenerativeInput(template_id) } DeclarationContext::PlainWire => { match io_kw { - Some((is_input, _)) => DeclarationPortInfo::RegularPort { is_input, port_id: PortID::PLACEHOLDER }, - None => DeclarationPortInfo::NotPort, + Some((is_input, _)) => DeclarationKind::RegularPort { is_input, port_id: PortID::PLACEHOLDER }, + None => DeclarationKind::NotPort, } } DeclarationContext::StructField => { if let Some((_, io_span)) = io_kw { self.errors.error(io_span, "Cannot declare 'input' or 'output' in a struct"); } - DeclarationPortInfo::StructField { field_id: UUID::PLACEHOLDER } + DeclarationKind::StructField { field_id: UUID::PLACEHOLDER } } }; @@ -611,19 +617,19 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { DeclarationContext::IO{is_input:_} | DeclarationContext::PlainWire | DeclarationContext::StructField => { match declaration_modifiers { Some((kw!("state"), modifier_span)) => { - if is_port.as_regular_port() == Some(true) { + if decl_kind.is_io_port() == Some(true) { self.errors.error(modifier_span, "Inputs cannot be decorated with 'state'"); } IdentifierType::State } Some((kw!("gen"), modifier_span)) => { - match is_port { - DeclarationPortInfo::NotPort => {} - DeclarationPortInfo::RegularPort { is_input : _, port_id : _ } | DeclarationPortInfo::StructField { field_id:_ } => { + match decl_kind { + DeclarationKind::NotPort => {} + DeclarationKind::RegularPort { is_input : _, port_id : _ } | DeclarationKind::StructField { field_id:_ } => { self.errors.error(modifier_span, "Cannot declare `gen` on inputs and outputs. To declare template inputs write it between the #()"); - is_port = DeclarationPortInfo::NotPort; // Make it not a port anymore, because it errored + decl_kind = DeclarationKind::NotPort; // Make it not a port anymore, because it errored } - DeclarationPortInfo::GenerativeInput(_) => unreachable!("Caught by DeclarationContext::ForLoopGenerative | DeclarationContext::TemplateGenerative(_)") + DeclarationKind::GenerativeInput(_) => unreachable!("Caught by DeclarationContext::ForLoopGenerative | DeclarationContext::TemplateGenerative(_)") } IdentifierType::Generative } @@ -641,15 +647,15 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { } }; - let alloc_domain_for = match &mut is_port { - DeclarationPortInfo::NotPort => if identifier_type.is_generative() { + let alloc_domain_for = match &mut decl_kind { + DeclarationKind::NotPort => if identifier_type.is_generative() { DomainAllocOption::Generative } else { DomainAllocOption::NonGenerativeUnknown }, - DeclarationPortInfo::GenerativeInput(_template_id) => {DomainAllocOption::Generative} - DeclarationPortInfo::StructField { field_id } => {*field_id = self.fields_to_visit.next().unwrap(); DomainAllocOption::NonGenerativeKnown(UUID::PLACEHOLDER)} - DeclarationPortInfo::RegularPort { is_input:_, port_id } => {*port_id = self.ports_to_visit.next().unwrap(); DomainAllocOption::NonGenerativeKnown(self.named_domain_alloc.peek())} + DeclarationKind::GenerativeInput(_template_id) => {DomainAllocOption::Generative} + DeclarationKind::StructField { field_id } => {*field_id = self.fields_to_visit.next().unwrap(); DomainAllocOption::NonGenerativeKnown(UUID::PLACEHOLDER)} + DeclarationKind::RegularPort { is_input:_, port_id } => {*port_id = self.ports_to_visit.next().unwrap(); DomainAllocOption::NonGenerativeKnown(self.named_domain_alloc.peek())} }; cursor.field(field!("type")); @@ -690,7 +696,7 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { let name = &self.globals.file_data.file_text[name_span]; - if is_port.implies_read_only() { + if decl_kind.implies_read_only() { read_only = true; } @@ -699,7 +705,7 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { typ : self.type_alloc.alloc_unset_type(alloc_domain_for), read_only, declaration_itself_is_not_written_to, - is_port, + decl_kind, identifier_type, name : name.to_owned(), name_span, @@ -724,10 +730,10 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { } fn alloc_error(&mut self, span: Span) -> FlatID { - self.instructions.alloc(Instruction::Wire(WireInstance { + self.instructions.alloc(Instruction::Expression(Expression { typ: self.type_alloc.alloc_unset_type(DomainAllocOption::NonGenerativeUnknown), span, - source: WireSource::new_error(), + source: ExpressionSource::new_error(), })) } @@ -761,7 +767,7 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { if arg_count != expected_arg_count { if arg_count > expected_arg_count { // Too many args, complain about excess args at the end - let excess_args_span = Span::new_overarching(self.instructions[arguments[expected_arg_count]].unwrap_wire().span, self.instructions[*arguments.last().unwrap()].unwrap_wire().span); + let excess_args_span = Span::new_overarching(self.instructions[arguments[expected_arg_count]].unwrap_expression().span, self.instructions[*arguments.last().unwrap()].unwrap_expression().span); self.errors .error(excess_args_span, format!("Excess argument. Function takes {expected_arg_count} args, but {arg_count} were passed.")) @@ -870,7 +876,7 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { let (source, is_generative) = if kind == kind!("number") { let text = &self.globals.file_data.file_text[expr_span]; use std::str::FromStr; - (WireSource::Constant(Value::Integer(BigInt::from_str(text).unwrap())), true) + (ExpressionSource::Constant(Value::Integer(BigInt::from_str(text).unwrap())), true) } else if kind == kind!("unary_op") { cursor.go_down_no_check(|cursor| { cursor.field(field!("operator")); @@ -879,7 +885,7 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { cursor.field(field!("right")); let (right, right_gen) = self.flatten_expr(cursor); - (WireSource::UnaryOp { op, right }, right_gen) + (ExpressionSource::UnaryOp { op, right }, right_gen) }) } else if kind == kind!("binary_op") { cursor.go_down_no_check(|cursor| { @@ -892,7 +898,7 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { cursor.field(field!("right")); let (right, right_gen) = self.flatten_expr(cursor); - (WireSource::BinaryOp { op, left, right }, left_gen & right_gen) + (ExpressionSource::BinaryOp { op, left, right }, left_gen & right_gen) }) } else if kind == kind!("func_call") { (if let Some(fc_id) = self.flatten_func_call(cursor) { @@ -905,7 +911,7 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { } if interface.func_call_outputs.len() >= 1 { - WireSource::WireRef(WireReference::simple_port(PortInfo { + ExpressionSource::WireRef(WireReference::simple_port(PortReference { submodule_name_span: fc.interface_reference.name_span, submodule_decl: fc.interface_reference.submodule_decl, port: interface.func_call_outputs.0, @@ -914,11 +920,11 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { })) } else { // Function desugaring or using threw an error - WireSource::new_error() + ExpressionSource::new_error() } } else { // Function desugaring or using threw an error - WireSource::new_error() + ExpressionSource::new_error() }, false) // TODO add compile-time functions https://github.com/pc2/sus-compiler/issues/10 } else if kind == kind!("parenthesis_expression") { // Explicitly return so we don't alloc another WireInstance Instruction @@ -928,7 +934,7 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { } else { if let Some(wr) = self.flatten_wire_reference(cursor).expect_wireref(self) { let mut is_comptime = match wr.root { - WireReferenceRoot::LocalDecl(uuid, _span) => self.instructions[uuid].unwrap_wire_declaration().identifier_type.is_generative(), + WireReferenceRoot::LocalDecl(uuid, _span) => self.instructions[uuid].unwrap_declaration().identifier_type.is_generative(), WireReferenceRoot::NamedConstant(_) => true, WireReferenceRoot::SubModulePort(_) => false, }; @@ -936,23 +942,23 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { for elem in &wr.path { match elem { WireReferencePathElement::ArrayAccess { idx, bracket_span:_ } => { - is_comptime &= self.instructions[*idx].unwrap_wire().typ.domain.is_generative() + is_comptime &= self.instructions[*idx].unwrap_expression().typ.domain.is_generative() } } } - (WireSource::WireRef(wr), is_comptime) + (ExpressionSource::WireRef(wr), is_comptime) } else { - (WireSource::new_error(), false) + (ExpressionSource::new_error(), false) } }; - let wire_instance = WireInstance { + let wire_instance = Expression { typ: self.type_alloc.alloc_unset_type(if is_generative {DomainAllocOption::Generative} else {DomainAllocOption::NonGenerativeUnknown}), span: expr_span, source, }; (self.instructions - .alloc(Instruction::Wire(wire_instance)), is_generative) + .alloc(Instruction::Expression(wire_instance)), is_generative) } fn flatten_wire_reference(&mut self, cursor: &mut Cursor) -> PartialWireReference { @@ -964,7 +970,7 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { let root = WireReferenceRoot::LocalDecl(decl_id, expr_span); PartialWireReference::WireReference(WireReference { root, - is_generative: self.instructions[decl_id].unwrap_wire_declaration().identifier_type.is_generative(), + is_generative: self.instructions[decl_id].unwrap_declaration().identifier_type.is_generative(), path: Vec::new(), }) } @@ -1054,7 +1060,7 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { match submod.get_port_or_interface_by_name(port_name_span, &self.globals.file_data.file_text, self.errors) { Some(PortOrInterface::Port(port)) => { - let port_info = PortInfo{ + let port_info = PortReference{ submodule_name_span : Some(submodule_name_span), submodule_decl, port, @@ -1190,10 +1196,10 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { for port in outputs { if let Some((Some((to, write_modifiers)), to_span)) = to_iter.next() { let from = - self.instructions.alloc(Instruction::Wire(WireInstance { + self.instructions.alloc(Instruction::Expression(Expression { typ: self.type_alloc.alloc_unset_type(DomainAllocOption::NonGenerativeUnknown), // TODO Generative Function Calls https://github.com/pc2/sus-compiler/issues/10 span: func_call_span, - source: WireSource::WireRef(WireReference::simple_port(PortInfo { + source: ExpressionSource::WireRef(WireReference::simple_port(PortReference { port, port_name_span: None, is_input: false, @@ -1216,10 +1222,10 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { }; for leftover_to in to_iter { if let (Some((to, write_modifiers)), to_span) = leftover_to { - let err_id = self.instructions.alloc(Instruction::Wire(WireInstance { + let err_id = self.instructions.alloc(Instruction::Expression(Expression { typ: self.type_alloc.alloc_unset_type(DomainAllocOption::NonGenerativeUnknown), span: func_call_span, - source: WireSource::new_error(), + source: ExpressionSource::new_error(), })); self.instructions.alloc(Instruction::Write(Write { from: err_id, @@ -1381,7 +1387,7 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { true, cursor, ); - let flat_root_decl = self.instructions[root].unwrap_wire_declaration(); + let flat_root_decl = self.instructions[root].unwrap_declaration(); let is_generative = flat_root_decl.identifier_type.is_generative(); Some(( WireReference { @@ -1489,7 +1495,7 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { declaration_runtime_depth: OnceCell::new(), read_only: false, declaration_itself_is_not_written_to: true, - is_port: DeclarationPortInfo::NotPort, + decl_kind: DeclarationKind::NotPort, identifier_type: IdentifierType::Generative, latency_specifier: None, documentation: const_type_cursor.extract_gathered_comments(), @@ -1566,20 +1572,20 @@ pub fn flatten_all_modules(linker: &mut Linker) { // Set all declaration_instruction values for (decl_id, instr) in &instructions { if let Instruction::Declaration(decl) = instr { - match decl.is_port { - DeclarationPortInfo::NotPort => {}, - DeclarationPortInfo::RegularPort { is_input:_, port_id } => { + match decl.decl_kind { + DeclarationKind::NotPort => {}, + DeclarationKind::RegularPort { is_input:_, port_id } => { let port = &mut md.ports[port_id]; assert_eq!(port.name_span, decl.name_span); port.declaration_instruction = decl_id; } - DeclarationPortInfo::GenerativeInput(this_template_id) => { + DeclarationKind::GenerativeInput(this_template_id) => { let TemplateInputKind::Generative(GenerativeTemplateInputKind { decl_span:_, declaration_instruction }) = &mut md.link_info.template_arguments[this_template_id].kind else {unreachable!()}; *declaration_instruction = decl_id; } - DeclarationPortInfo::StructField { field_id:_ } => unreachable!("No Struct fields in Modules") + DeclarationKind::StructField { field_id:_ } => unreachable!("No Struct fields in Modules") } } } @@ -1600,15 +1606,15 @@ pub fn flatten_all_modules(linker: &mut Linker) { // Set all declaration_instruction values for (decl_id, instr) in &instructions { if let Instruction::Declaration(decl) = instr { - match decl.is_port { - DeclarationPortInfo::NotPort => {assert!(decl.identifier_type == IdentifierType::Generative, "If a variable isn't generative, then it MUST be a struct field")} - DeclarationPortInfo::StructField { field_id } => { + match decl.decl_kind { + DeclarationKind::NotPort => {assert!(decl.identifier_type == IdentifierType::Generative, "If a variable isn't generative, then it MUST be a struct field")} + DeclarationKind::StructField { field_id } => { let field = &mut typ.fields[field_id]; assert_eq!(field.name_span, decl.name_span); field.declaration_instruction = decl_id; } - DeclarationPortInfo::RegularPort { is_input:_, port_id:_ } => {unreachable!("No ports in structs")} - DeclarationPortInfo::GenerativeInput(this_template_id) => { + DeclarationKind::RegularPort { is_input:_, port_id:_ } => {unreachable!("No ports in structs")} + DeclarationKind::GenerativeInput(this_template_id) => { let TemplateInputKind::Generative(GenerativeTemplateInputKind { decl_span:_, declaration_instruction }) = &mut typ.link_info.template_arguments[this_template_id].kind else {unreachable!()}; diff --git a/src/flattening/lints.rs b/src/flattening/lints.rs index 682d520..9657560 100644 --- a/src/flattening/lints.rs +++ b/src/flattening/lints.rs @@ -102,7 +102,7 @@ fn make_fanins(instructions: &FlatAlloc) -> FlatAlloc Instruction::Declaration(decl) => { decl.typ_expr.for_each_generative_input(&mut collector_func); } - Instruction::Wire(wire) => { + Instruction::Expression(wire) => { wire.source.for_each_dependency(collector_func); } Instruction::IfStatement(stm) => { diff --git a/src/flattening/mod.rs b/src/flattening/mod.rs index 16a6622..2988876 100644 --- a/src/flattening/mod.rs +++ b/src/flattening/mod.rs @@ -82,7 +82,7 @@ impl Module { pub fn get_port_decl(&self, port: PortID) -> &Declaration { let flat_port = self.ports[port].declaration_instruction; - self.link_info.instructions[flat_port].unwrap_wire_declaration() + self.link_info.instructions[flat_port].unwrap_declaration() } /// Get a port by the given name. Reports non existing ports errors @@ -122,7 +122,7 @@ impl Module { Instruction::SubModule(sm) => sm.module_ref.get_total_span(), Instruction::FuncCall(fc) => fc.whole_func_span, Instruction::Declaration(decl) => decl.decl_span, - Instruction::Wire(w) => w.span, + Instruction::Expression(w) => w.span, Instruction::Write(conn) => conn.to_span, Instruction::IfStatement(if_stmt) => self.get_instruction_span(if_stmt.condition), Instruction::ForStatement(for_stmt) => { @@ -136,6 +136,9 @@ impl Module { } } +/// Represents an opaque type in the compiler, like `int` or `bool`. +/// +/// TODO: Structs #8 #[derive(Debug)] pub struct StructType { /// Created in Stage 1: Initialization @@ -168,6 +171,7 @@ pub struct DomainInfo { pub name: String, } +/// With this struct, we convert the domains of a submodule, to their connecting domains in the containing module #[derive(Clone, Copy)] pub struct InterfaceToDomainMap<'linker> { pub local_domain_map: &'linker FlatAlloc, @@ -201,6 +205,27 @@ impl IdentifierType { } } +/// A port of a module. Not to be confused with [PortReference], which is a reference to a submodule port. +/// +/// All ports must have a name +/// +/// ```sus +/// module md { +/// interface beep : int a -> bool b, int[3] c +/// +/// output int d +/// } +/// ``` +/// +/// Creates four ports: a, b, c, and d. +/// +/// Ports can be part of interfaces, as is the case above, or are standalone, like d +/// +/// ```sus +/// module md { +/// interface beep : int a -> bool b, int[3] c +/// } +/// ``` #[derive(Debug)] pub struct Port { pub name: String, @@ -208,10 +233,27 @@ pub struct Port { pub decl_span: Span, pub is_input: bool, pub domain: DomainID, - /// This is only set after flattening is done. Initially just [UUID::PLACEHOLDER] + /// This is only set after flattening is done. Initially just [crate::alloc::UUID::PLACEHOLDER] pub declaration_instruction: FlatID, } +/// An interface, like: +/// +/// ```sus +/// module md { +/// interface beep : int a -> bool b, int[3] c +/// } +/// ``` +/// +/// So this struct represents an interface, which always can be called with a method-call notation: +/// +/// ```sus +/// module use_md { +/// md x +/// +/// bool xyz, int[3] pqr = x.beep(3) +/// } +/// ``` #[derive(Debug)] pub struct Interface { pub name_span: Span, @@ -255,7 +297,7 @@ impl WireReferencePathElement { pub enum WireReferenceRoot { LocalDecl(FlatID, Span), NamedConstant(GlobalReference), - SubModulePort(PortInfo), + SubModulePort(PortReference), } impl WireReferenceRoot { @@ -277,7 +319,7 @@ impl WireReferenceRoot { /// References to wires /// -/// Example: myModule.port[a][b:c] +/// Example: `myModule.port[a][b:c]` #[derive(Debug)] pub struct WireReference { pub root: WireReferenceRoot, @@ -286,7 +328,7 @@ pub struct WireReference { } impl WireReference { - fn simple_port(port: PortInfo) -> WireReference { + fn simple_port(port: PortReference) -> WireReference { WireReference { root: WireReferenceRoot::SubModulePort(port), is_generative: false, @@ -317,6 +359,15 @@ impl WriteModifiers { } } +/// An [Instruction] that refers to an assignment +/// +/// ```sus +/// module md { +/// int x = 3 // first write +/// +/// int b, int c = someFunc(3) // Two writes, one to b, one to c +/// } +/// ``` #[derive(Debug)] pub struct Write { pub from: FlatID, @@ -363,8 +414,9 @@ pub enum BinaryOperator { LesserEq, } +/// A reference to a port within a submodule. Not to be confused with [Port], which is the declaration of the port itself in the [Module] #[derive(Debug, Clone, Copy)] -pub struct PortInfo { +pub struct PortReference { pub submodule_decl: FlatID, pub port: PortID, pub is_input: bool, @@ -376,15 +428,16 @@ pub struct PortInfo { pub submodule_name_span: Option, } +/// An [Instruction] that represents a single expression in the program. Like ((3) + (x)) #[derive(Debug)] -pub struct WireInstance { +pub struct Expression { pub typ: FullType, pub span: Span, - pub source: WireSource, + pub source: ExpressionSource, } #[derive(Debug)] -pub enum WireSource { +pub enum ExpressionSource { WireRef(WireReference), // Used to add a span to the reference of a wire. UnaryOp { op: UnaryOperator, @@ -398,12 +451,16 @@ pub enum WireSource { Constant(Value), } -impl WireSource { - pub const fn new_error() -> WireSource { - WireSource::Constant(Value::Error) +impl ExpressionSource { + pub const fn new_error() -> ExpressionSource { + ExpressionSource::Constant(Value::Error) } } +/// The textual representation of a type expression in the source code. +/// +/// Not to be confused with [crate::typing::abstract_type::AbstractType] which is for working with types in the flattening stage, +/// or [crate::typing::concrete_type::ConcreteType], which is for working with types post instantiation. #[derive(Debug)] pub enum WrittenType { Error(Span), @@ -423,17 +480,19 @@ impl WrittenType { } } +/// Little helper struct that tells us what kind of declaration it is. Is it a Port, Template argument, A struct field, or just a regular temporary? #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum DeclarationPortInfo { +pub enum DeclarationKind { NotPort, StructField { field_id : FieldID }, RegularPort { is_input: bool, port_id: PortID }, GenerativeInput(TemplateID), } -impl DeclarationPortInfo { - pub fn as_regular_port(&self) -> Option { - if let DeclarationPortInfo::RegularPort { +impl DeclarationKind { + /// Basically an unwrap to see if this [Declaration] refers to a [Port], and returns `Some(is_input)` if so. + pub fn is_io_port(&self) -> Option { + if let DeclarationKind::RegularPort { is_input, port_id: _, } = self @@ -445,17 +504,22 @@ impl DeclarationPortInfo { } pub fn implies_read_only(&self) -> bool { match self { - DeclarationPortInfo::NotPort => false, - DeclarationPortInfo::StructField { field_id:_ } => false, - DeclarationPortInfo::RegularPort { + DeclarationKind::NotPort => false, + DeclarationKind::StructField { field_id:_ } => false, + DeclarationKind::RegularPort { is_input, port_id: _, } => *is_input, - DeclarationPortInfo::GenerativeInput(_) => true, + DeclarationKind::GenerativeInput(_) => true, } } } +/// An [Instruction] that represents a declaration of a new local variable. +/// +/// It can be referenced by a [WireReferenceRoot::LocalDecl] +/// +/// A Declaration Instruction always corresponds to a new entry in the [self::name_context::LocalVariableContext]. #[derive(Debug)] pub struct Declaration { pub typ_expr: WrittenType, @@ -470,12 +534,17 @@ pub struct Declaration { pub read_only: bool, /// If the program text already covers the write, then lsp stuff on this declaration shouldn't use it. pub declaration_itself_is_not_written_to: bool, - pub is_port: DeclarationPortInfo, + pub decl_kind: DeclarationKind, pub identifier_type: IdentifierType, pub latency_specifier: Option, pub documentation: Documentation, } +/// An [Instruction] that represents a instantiation of a submodule. +/// +/// It can be referenced by a [WireReferenceRoot::SubModulePort] +/// +/// A SubModuleInstance Instruction always corresponds to a new entry in the [self::name_context::LocalVariableContext]. #[derive(Debug)] pub struct SubModuleInstance { pub module_ref: GlobalReference, @@ -506,6 +575,7 @@ impl SubModuleInstance { } } +/// See [FuncCallInstruction] #[derive(Debug)] pub struct ModuleInterfaceReference { pub submodule_decl: FlatID, @@ -520,6 +590,47 @@ pub struct ModuleInterfaceReference { pub interface_span: Span, } +/// An [Instruction] that represents the calling on an interface of a [SubModuleInstance]. +/// It is the connecting of multiple input ports, and output ports on a submodule in one statement. +/// +/// One may ask, why is this not simply part of [Expression]? +/// That is because an Expression can only represent one output. Workarounds like putting multiple outputs +/// together in a tuple would not work, because: +/// - The function call syntax is just a convenient syntax sugar for connecting multiple inputs and outputs simultaneously. +/// We want to conceptually keep the signals separate. Both input and output signals, while keeping the function call syntax that programmers are used to. +/// - Forcing all outputs together into one type would bind them together for latency counting, which we don't want +/// - We don't have tuple types +/// +/// The outputs of a function call are collected with [Write] instructions over the outputs of the underlying [SubModuleInstance] +/// +/// Function calls can come in three forms: +/// +/// ```sus +/// module xor { +/// interface xor : bool a, bool b -> bool c +/// } +/// +/// module fifo #(T) { +/// interface push : bool push, T data +/// interface pop : bool pop -> bool valid, T data +/// } +/// +/// module use_modules { +/// // We can use functions inline +/// bool x = xor(true, false) +/// +/// // Declare the submodule explicitly +/// xor xor_inst +/// bool y = xor_inst(true, false) +/// +/// // Or access interfaces explicitly +/// fifo my_fifo +/// bool z, int data = my_fifo.pop() +/// +/// // Finally, if a function returns a single argument, we can call it inline in an expression: +/// bool w = true | xor(true, false) +/// } +/// ``` #[derive(Debug)] pub struct FuncCallInstruction { pub interface_reference: ModuleInterfaceReference, @@ -539,6 +650,7 @@ impl FuncCallInstruction { } } +/// A control-flow altering [Instruction] to represent compiletime and runtime if & when statements. #[derive(Debug)] pub struct IfStatement { pub condition: FlatID, @@ -548,8 +660,8 @@ pub struct IfStatement { pub else_end: FlatID, } +/// A control-flow altering [Instruction] to represent compiletime looping on a generative index #[derive(Debug)] -// Always is_compiletime pub struct ForStatement { pub loop_var_decl: FlatID, pub start: FlatID, @@ -557,12 +669,22 @@ pub struct ForStatement { pub loop_body: FlatIDRange, } +/// When a module has been parsed and flattened, it is turned into a large list of instructions, +/// These are stored in [LinkInfo::instructions]`: FlatAlloc` +/// +/// Instructions are indexed with [FlatID] +/// +/// One may ask: Why have [Expression], [WrittenType], etc refer to others by [FlatID], instead of a recursive datastructure? +/// The reason is that later representations, such as [crate::instantiation::RealWire] and other structures can still refer to intermediate parts of expressions +/// They can simply refer to the [FlatID] of these instructions, instead of some convoluted other representation. +/// +/// When executing, the instructions are processed in order. Control flow instructions like [IfStatement] and [ForStatement] can cause the executor to repeat or skip sections. #[derive(Debug)] pub enum Instruction { SubModule(SubModuleInstance), FuncCall(FuncCallInstruction), Declaration(Declaration), - Wire(WireInstance), + Expression(Expression), Write(Write), IfStatement(IfStatement), ForStatement(ForStatement), @@ -570,18 +692,18 @@ pub enum Instruction { impl Instruction { #[track_caller] - pub fn unwrap_wire(&self) -> &WireInstance { - let Self::Wire(w) = self else { - panic!("unwrap_wire on not a wire! Found {self:?}") + pub fn unwrap_expression(&self) -> &Expression { + let Self::Expression(expr) = self else { + panic!("unwrap_expression on not a expression! Found {self:?}") }; - w + expr } #[track_caller] - pub fn unwrap_wire_declaration(&self) -> &Declaration { - let Self::Declaration(w) = self else { - panic!("unwrap_wire_declaration on not a WireDeclaration! Found {self:?}") + pub fn unwrap_declaration(&self) -> &Declaration { + let Self::Declaration(decl) = self else { + panic!("unwrap_declaration on not a Declaration! Found {self:?}") }; - w + decl } #[track_caller] pub fn unwrap_submodule(&self) -> &SubModuleInstance { @@ -599,12 +721,10 @@ impl Instruction { } } -#[derive(Debug)] -pub enum ModuleOrWrittenType { - WrittenType(WrittenType), - Module(GlobalReference), -} - +/// Small wrapper struct for allocating the Hindley-Milner variables +/// required for [crate::typing::abstract_type::AbstractType::Unknown] and [DomainType::DomainVariable] +/// +/// See [crate::typing::type_inference::HindleyMilner] #[derive(Debug, Clone)] pub struct TypingAllocator { pub type_variable_alloc: UUIDAllocator, diff --git a/src/flattening/name_context.rs b/src/flattening/name_context.rs index 264d1f1..b053d0b 100644 --- a/src/flattening/name_context.rs +++ b/src/flattening/name_context.rs @@ -1,3 +1,11 @@ + +/// This keeps track of the variables that are in the current scope. +/// +/// Each [super::Declaration] and [super::SubModuleInstance] should be added here at some point +/// +/// Must be maintained manually. +/// When a new scope is entered, call [Self::new_frame], +/// when exiting a scope call [Self::pop_frame] pub struct LocalVariableContext<'file, Obj: Copy> { local_stack: Vec<(&'file str, Obj)>, current_frame_starts_at: usize, diff --git a/src/flattening/parser.rs b/src/flattening/parser.rs index f53334c..16e7264 100644 --- a/src/flattening/parser.rs +++ b/src/flattening/parser.rs @@ -31,6 +31,11 @@ fn print_current_node_indented<'ft>(file_text: &'ft FileText, cursor: &TreeCurso node_name } +/// Wraps the tree-sitter [TreeCursor] for a more functional-style interface. +/// +/// Especially with regards to going up and down the syntax tree, this module provides [Self::go_down] and friends. +/// +/// This module also handles documentation comment gathering #[derive(Clone)] pub struct Cursor<'t> { cursor: TreeCursor<'t>, diff --git a/src/flattening/typechecking.rs b/src/flattening/typechecking.rs index 57e2191..8c2dc04 100644 --- a/src/flattening/typechecking.rs +++ b/src/flattening/typechecking.rs @@ -108,7 +108,7 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { ) -> ErrorInfo { match wire_ref_root { WireReferenceRoot::LocalDecl(id, _) => { - let decl_root = self.working_on.instructions[*id].unwrap_wire_declaration(); + let decl_root = self.working_on.instructions[*id].unwrap_declaration(); decl_root.make_info(self.errors.file) } WireReferenceRoot::NamedConstant(cst) => { @@ -140,12 +140,12 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { fn typecheck_wire_reference(&self, wire_ref: &WireReference, whole_span: Span, output_typ: &FullType) { let root_type = match &wire_ref.root { WireReferenceRoot::LocalDecl(id, _) => { - let decl_root = self.working_on.instructions[*id].unwrap_wire_declaration(); + let decl_root = self.working_on.instructions[*id].unwrap_declaration(); decl_root.typ.clone() } WireReferenceRoot::NamedConstant(cst) => { let linker_cst = &self.globals[cst.id]; - let decl = linker_cst.link_info.instructions[linker_cst.output_decl].unwrap_wire_declaration(); + let decl = linker_cst.link_info.instructions[linker_cst.output_decl].unwrap_declaration(); let typ = AbstractType::Unknown(self.type_checker.alloc_typ_variable()); self.type_checker.unify_with_written_type_substitute_templates_must_succeed(&decl.typ_expr, &typ, &cst.template_arg_types); FullType { @@ -163,19 +163,19 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { for p in &wire_ref.path { match p { &WireReferencePathElement::ArrayAccess { idx, bracket_span } => { - let idx_wire = self.working_on.instructions[idx].unwrap_wire(); + let idx_expr = self.working_on.instructions[idx].unwrap_expression(); let new_resulting_variable = AbstractType::Unknown(self.type_checker.alloc_typ_variable()); let arr_span = bracket_span.outer_span(); self.type_checker.typecheck_array_access( ¤t_type_in_progress, - &idx_wire.typ.typ, + &idx_expr.typ.typ, arr_span, - idx_wire.span, + idx_expr.span, &new_resulting_variable ); - self.type_checker.unify_domains(&idx_wire.typ.domain, &output_typ.domain, idx_wire.span, "array access index"); + self.type_checker.unify_domains(&idx_expr.typ.domain, &output_typ.domain, idx_expr.span, "array access index"); current_type_in_progress = new_resulting_variable; } } @@ -200,11 +200,11 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { // For both runtime, and compiletime declarations. decl.declaration_runtime_depth.set(self.runtime_condition_stack.len()).unwrap(); } - Instruction::Wire(_) => {} + Instruction::Expression(_) => {} Instruction::Write(conn) => { let (decl, file) = match &conn.to.root { WireReferenceRoot::LocalDecl(decl_id, _) => { - let decl = self.working_on.instructions[*decl_id].unwrap_wire_declaration(); + let decl = self.working_on.instructions[*decl_id].unwrap_declaration(); if decl.read_only { self.errors .error(conn.to_span, format!("'{}' is read-only", decl.name)) @@ -219,7 +219,7 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { WireReferenceRoot::SubModulePort(port) => { let module_port_decl = self.get_decl_of_module_port(port.port, port.submodule_decl); - if !module_port_decl.0.is_port.as_regular_port().unwrap() { + if !module_port_decl.0.decl_kind.is_io_port().unwrap() { self.errors .error(conn.to_span, "Cannot assign to a submodule output port") .info_obj_different_file(module_port_decl.0, module_port_decl.1); @@ -238,7 +238,7 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { // Check that this generative declaration isn't used in a non-compiletime if if let Some(root_flat) = conn.to.root.get_root_flat() { let to_decl = self.working_on.instructions[root_flat] - .unwrap_wire_declaration(); + .unwrap_declaration(); let found_decl_depth = *to_decl.declaration_runtime_depth.get().unwrap(); if self.runtime_condition_stack.len() > found_decl_depth @@ -267,12 +267,12 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { } } Instruction::IfStatement(if_stmt) => { - let condition_wire = self.working_on.instructions[if_stmt.condition].unwrap_wire(); - if !condition_wire.typ.domain.is_generative() { + let condition_expr = self.working_on.instructions[if_stmt.condition].unwrap_expression(); + if !condition_expr.typ.domain.is_generative() { self.runtime_condition_stack.push(ConditionStackElem { ends_at: if_stmt.else_end, - span: condition_wire.span, - domain: condition_wire.typ.domain.clone(), + span: condition_expr.span, + domain: condition_expr.typ.domain.clone(), }); } } @@ -292,7 +292,7 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { match ¶meter.kind { TemplateInputKind::Type(_) => {} // Do nothing, nothing to unify with. Maybe in the future traits? TemplateInputKind::Generative(template_input) => { - let decl = target_link_info.instructions[template_input.declaration_instruction].unwrap_wire_declaration(); + let decl = target_link_info.instructions[template_input.declaration_instruction].unwrap_declaration(); self.type_checker.unify_with_written_type_substitute_templates_must_succeed( &decl.typ_expr, @@ -312,12 +312,12 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { self.type_checker.unify_with_written_type_must_succeed(wr_typ, argument_type); } TemplateArgKind::Value(val) => { - let val_wire = self.working_on.instructions[*val].unwrap_wire(); + let argument_expr = self.working_on.instructions[*val].unwrap_expression(); self.type_checker.typecheck_write_to_abstract( - &val_wire.typ.typ, + &argument_expr.typ.typ, &argument_type, - val_wire.span, + argument_expr.span, "generative template argument" ); } @@ -342,11 +342,11 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { self.typecheck_written_type(content_typ); - let idx_wire = self.working_on.instructions[*arr_idx].unwrap_wire(); + let idx_expr = self.working_on.instructions[*arr_idx].unwrap_expression(); self.type_checker.typecheck_write_to_abstract( - &idx_wire.typ.typ, + &idx_expr.typ.typ, &INT_TYPE, - idx_wire.span, + idx_expr.span, "array size" ); } @@ -374,12 +374,12 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { } Instruction::Declaration(decl) => { if let Some(latency_spec) = decl.latency_specifier { - let latency_spec_wire = - self.working_on.instructions[latency_spec].unwrap_wire(); + let latency_specifier_expr = + self.working_on.instructions[latency_spec].unwrap_expression(); self.type_checker.typecheck_write_to_abstract( - &latency_spec_wire.typ.typ, + &latency_specifier_expr.typ.typ, &INT_TYPE, - latency_spec_wire.span, + latency_specifier_expr.span, "latency specifier" ); } @@ -390,18 +390,18 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { self.type_checker.unify_with_written_type_must_succeed(&decl.typ_expr, &decl.typ.typ); } Instruction::IfStatement(stm) => { - let wire = &self.working_on.instructions[stm.condition].unwrap_wire(); + let condition_expr = &self.working_on.instructions[stm.condition].unwrap_expression(); self.type_checker.typecheck_write_to_abstract( - &wire.typ.typ, + &condition_expr.typ.typ, &BOOL_TYPE, - wire.span, + condition_expr.span, "if statement condition" ); } Instruction::ForStatement(stm) => { - let loop_var = self.working_on.instructions[stm.loop_var_decl].unwrap_wire_declaration(); - let start = self.working_on.instructions[stm.start].unwrap_wire(); - let end = self.working_on.instructions[stm.end].unwrap_wire(); + let loop_var = self.working_on.instructions[stm.loop_var_decl].unwrap_declaration(); + let start = self.working_on.instructions[stm.start].unwrap_expression(); + let end = self.working_on.instructions[stm.end].unwrap_expression(); self.type_checker.typecheck_write_to_abstract( &start.typ.typ, @@ -416,33 +416,33 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { "for loop end" ); } - Instruction::Wire(w) => { - match &w.source { - WireSource::WireRef(from_wire) => { - self.typecheck_wire_reference(from_wire, w.span, &w.typ); + Instruction::Expression(expr) => { + match &expr.source { + ExpressionSource::WireRef(from_wire) => { + self.typecheck_wire_reference(from_wire, expr.span, &expr.typ); } - &WireSource::UnaryOp { op, right } => { - let right_wire = self.working_on.instructions[right].unwrap_wire(); + &ExpressionSource::UnaryOp { op, right } => { + let right_expr = self.working_on.instructions[right].unwrap_expression(); self.type_checker.typecheck_unary_operator( op, - &right_wire.typ, - &w.typ, - right_wire.span + &right_expr.typ, + &expr.typ, + right_expr.span ); } - &WireSource::BinaryOp { op, left, right } => { - let left_wire = self.working_on.instructions[left].unwrap_wire(); - let right_wire = self.working_on.instructions[right].unwrap_wire(); + &ExpressionSource::BinaryOp { op, left, right } => { + let left_expr = self.working_on.instructions[left].unwrap_expression(); + let right_expr = self.working_on.instructions[right].unwrap_expression(); self.type_checker.typecheck_binary_operator( op, - &left_wire.typ, - &right_wire.typ, - left_wire.span, - right_wire.span, - &w.typ + &left_expr.typ, + &right_expr.typ, + left_expr.span, + right_expr.span, + &expr.typ ) } - WireSource::Constant(value) => self.type_checker.unify_with_constant(&w.typ.typ, value, w.span), + ExpressionSource::Constant(value) => self.type_checker.unify_with_constant(&expr.typ.typ, value, expr.span), }; } Instruction::FuncCall(fc) => { @@ -454,13 +454,13 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { self.get_decl_of_module_port(port, fc.interface_reference.submodule_decl); // Typecheck the value with target type - let from_wire = self.working_on.instructions[*arg].unwrap_wire(); + let from_expr = self.working_on.instructions[*arg].unwrap_expression(); - self.join_with_condition(&write_to_type.domain, from_wire.span.debug()); + self.join_with_condition(&write_to_type.domain, from_expr.span.debug()); self.type_checker.typecheck_write_to( - &from_wire.typ, + &from_expr.typ, &write_to_type, - from_wire.span, + from_expr.span, || { ("function argument".to_string(), vec![decl.make_info(file)]) } @@ -469,17 +469,17 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { } Instruction::Write(conn) => { // Typecheck the value with target type - let from_wire = self.working_on.instructions[conn.from].unwrap_wire(); + let from_expr = self.working_on.instructions[conn.from].unwrap_expression(); // Typecheck digging down into write side self.typecheck_wire_reference(&conn.to, conn.to_span, &conn.to_type); self.join_with_condition(&conn.to_type.domain, conn.to_span.debug()); - from_wire.span.debug(); + from_expr.span.debug(); self.type_checker.typecheck_write_to( - &from_wire.typ, + &from_expr.typ, &conn.to_type, - from_wire.span, + from_expr.span, || { let write_context = match conn.write_modifiers { WriteModifiers::Connection {..} => "connection", @@ -539,9 +539,9 @@ pub fn apply_types( // Post type application. Solidify types and flag any remaining AbstractType::Unknown for (_id, inst) in working_on.link_info.instructions.iter_mut() { match inst { - Instruction::Wire(w) => { - type_checker.finalize_type(types, &mut w.typ, w.span, errors); - if let WireSource::WireRef(wr) = &mut w.source { + Instruction::Expression(expr) => { + type_checker.finalize_type(types, &mut expr.typ, expr.span, errors); + if let ExpressionSource::WireRef(wr) = &mut expr.source { if let WireReferenceRoot::NamedConstant(cst) = &mut wr.root { type_checker.finalize_global_ref(types, cst, errors); } diff --git a/src/flattening/walk.rs b/src/flattening/walk.rs index e187fa4..1a7ff2e 100644 --- a/src/flattening/walk.rs +++ b/src/flattening/walk.rs @@ -2,13 +2,13 @@ use crate::typing::template::{TemplateArgKind, TemplateArgs}; use crate::prelude::*; -use super::{WireReferencePathElement, WireReferenceRoot, WireSource, WrittenType}; +use super::{WireReferencePathElement, WireReferenceRoot, ExpressionSource, WrittenType}; -impl WireSource { +impl ExpressionSource { /// Enumerates all instructions that this instruction depends on. This includes (maybe compiletime) wires, and submodules. pub fn for_each_dependency(&self, mut func: F) { match self { - WireSource::WireRef(wire_ref) => { + ExpressionSource::WireRef(wire_ref) => { match &wire_ref.root { WireReferenceRoot::LocalDecl(decl_id, _) => func(*decl_id), WireReferenceRoot::NamedConstant(_) => {} @@ -25,12 +25,12 @@ impl WireSource { } } } - &WireSource::UnaryOp { op: _, right } => func(right), - &WireSource::BinaryOp { op: _, left, right } => { + &ExpressionSource::UnaryOp { op: _, right } => func(right), + &ExpressionSource::BinaryOp { op: _, left, right } => { func(left); func(right) } - WireSource::Constant(_) => {} + ExpressionSource::Constant(_) => {} } } } diff --git a/src/instantiation/concrete_typecheck.rs b/src/instantiation/concrete_typecheck.rs index 2a7c2f6..ee8718c 100644 --- a/src/instantiation/concrete_typecheck.rs +++ b/src/instantiation/concrete_typecheck.rs @@ -2,7 +2,7 @@ use std::ops::Deref; use crate::errors::ErrorInfoObject; -use crate::flattening::{DeclarationPortInfo, WireReferenceRoot, WireSource, WrittenType}; +use crate::flattening::{DeclarationKind, WireReferenceRoot, ExpressionSource, WrittenType}; use crate::linker::LinkInfo; use crate::typing::template::{ConcreteTemplateArg, HowDoWeKnowTheTemplateArg}; use crate::typing::{ @@ -53,7 +53,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { assert!(is_state.is_of_type(&this_wire.typ)); } for s in sources { - let source_typ = &self.wires[s.from.from].typ; + let source_typ = &self.wires[s.from].typ; let destination_typ = self.walk_type_along_path(self.wires[this_wire_id].typ.clone(), &s.to_path); self.type_substitutor.unify_report_error(&destination_typ, &source_typ, span, "write wire access"); } @@ -163,19 +163,19 @@ struct SubmoduleTypecheckConstraint { /// output int total /// } /// ``` -fn can_wire_can_be_value_inferred(link_info: &LinkInfo, flat_wire: FlatID) -> Option { - let wire = link_info.instructions[flat_wire].unwrap_wire(); - let WireSource::WireRef(wr) = &wire.source else {return None}; +fn can_expression_be_value_inferred(link_info: &LinkInfo, expr_id: FlatID) -> Option { + let expr = link_info.instructions[expr_id].unwrap_expression(); + let ExpressionSource::WireRef(wr) = &expr.source else {return None}; if !wr.path.is_empty() {return None} // Must be a plain, no fuss reference to a de let WireReferenceRoot::LocalDecl(wire_declaration, _span) = &wr.root else {return None}; - let template_arg_decl = link_info.instructions[*wire_declaration].unwrap_wire_declaration(); - let DeclarationPortInfo::GenerativeInput(template_id) = &template_arg_decl.is_port else {return None}; + let template_arg_decl = link_info.instructions[*wire_declaration].unwrap_declaration(); + let DeclarationKind::GenerativeInput(template_id) = &template_arg_decl.decl_kind else {return None}; Some(*template_id) } fn try_to_attach_value_to_template_arg(template_wire_referernce: FlatID, found_value: &ConcreteType, template_args: &mut ConcreteTemplateArgs, submodule_link_info: &LinkInfo) { let ConcreteType::Value(v) = found_value else {return}; // We don't have a value to assign - if let Some(template_id) = can_wire_can_be_value_inferred(submodule_link_info, template_wire_referernce) { + if let Some(template_id) = can_expression_be_value_inferred(submodule_link_info, template_wire_referernce) { if let ConcreteTemplateArg::NotProvided = &template_args[template_id] { template_args[template_id] = ConcreteTemplateArg::Value(TypedValue::from_value(v.clone()), HowDoWeKnowTheTemplateArg::Inferred) } @@ -218,7 +218,7 @@ impl SubmoduleTypecheckConstraint { wire_typ_clone.fully_substitute(&context.type_substitutor); let port_decl_instr = sub_module.ports[id].declaration_instruction; - let port_decl = sub_module.link_info.instructions[port_decl_instr].unwrap_wire_declaration(); + let port_decl = sub_module.link_info.instructions[port_decl_instr].unwrap_declaration(); infer_parameters_by_walking_type(&port_decl.typ_expr, &wire_typ_clone, &mut sm.template_args, &sub_module.link_info); } diff --git a/src/instantiation/execute.rs b/src/instantiation/execute.rs index b258b6b..6e70bbc 100644 --- a/src/instantiation/execute.rs +++ b/src/instantiation/execute.rs @@ -40,7 +40,7 @@ impl<'fl> GenerationState<'fl> { let instr = &self.md.link_info.instructions[v]; match instr { Instruction::Declaration(d) => d.name_span, - Instruction::Wire(w) => w.span, + Instruction::Expression(expr) => expr.span, _ => unreachable!(), } } @@ -265,13 +265,6 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { num_regs: i64, original_instruction: FlatID, ) { - let from = ConnectFrom { - num_regs, - from, - condition : self.condition_stack.clone().into_boxed_slice(), - original_connection: original_instruction, - }; - let RealWireDataSource::Multiplexer { is_state: _, sources, @@ -280,7 +273,13 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { caught_by_typecheck!("Should only be a writeable wire here") }; - sources.push(MultiplexerSource { from, to_path }); + sources.push(MultiplexerSource { + to_path, + num_regs, + from, + condition : self.condition_stack.clone().into_boxed_slice(), + original_connection: original_instruction, + }); } fn instantiate_connection( @@ -391,14 +390,14 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { Ok(work_on_value) } - fn compute_compile_time(&mut self, wire_inst: &WireInstance) -> ExecutionResult { - Ok(match &wire_inst.source { - WireSource::WireRef(wire_ref) => self.compute_compile_time_wireref(wire_ref)?, - &WireSource::UnaryOp { op, right } => { + fn compute_compile_time(&mut self, expression: &Expression) -> ExecutionResult { + Ok(match &expression.source { + ExpressionSource::WireRef(wire_ref) => self.compute_compile_time_wireref(wire_ref)?, + &ExpressionSource::UnaryOp { op, right } => { let right_val = self.generation_state.get_generation_value(right)?; compute_unary_op(op, right_val) } - &WireSource::BinaryOp { op, left, right } => { + &ExpressionSource::BinaryOp { op, left, right } => { let left_val = self.generation_state.get_generation_value(left)?; let right_val = self.generation_state.get_generation_value(right)?; @@ -407,7 +406,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { use num::Zero; if right_val.value.unwrap_integer().is_zero() { return Err(( - wire_inst.span, + expression.span, format!( "Divide or Modulo by zero: {} / 0", left_val.unwrap_integer() @@ -420,7 +419,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { compute_binary_op(left_val, op, right_val) } - WireSource::Constant(value) => TypedValue::from_value(value.clone()), + ExpressionSource::Constant(value) => TypedValue::from_value(value.clone()), }) } fn alloc_wire_for_const( @@ -501,7 +500,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { Vec::new() }; - *wire_found = Some(UsedPort { + *wire_found = Some(SubModulePort { maps_to_wire: new_wire, name_refs, }); @@ -533,14 +532,14 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { ), } } - fn wire_to_real_wire( + fn expression_to_real_wire( &mut self, - w: &WireInstance, + expression: &Expression, original_instruction: FlatID, domain: DomainID, ) -> ExecutionResult { - let source = match &w.source { - WireSource::WireRef(wire_ref) => { + let source = match &expression.source { + ExpressionSource::WireRef(wire_ref) => { let (root_wire, path_preamble) = self.get_wire_ref_root_as_wire(&wire_ref.root, original_instruction, domain); let path = self.instantiate_wire_ref_path(path_preamble, &wire_ref.path, domain); @@ -555,16 +554,16 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { path, } } - &WireSource::UnaryOp { op, right } => { + &ExpressionSource::UnaryOp { op, right } => { let right = self.get_wire_or_constant_as_wire(right, domain); RealWireDataSource::UnaryOp { op, right } } - &WireSource::BinaryOp { op, left, right } => { + &ExpressionSource::BinaryOp { op, left, right } => { let left = self.get_wire_or_constant_as_wire(left, domain); let right = self.get_wire_or_constant_as_wire(right, domain); RealWireDataSource::BinaryOp { op, left, right } } - WireSource::Constant(_) => { + ExpressionSource::Constant(_) => { unreachable!("Constant cannot be non-compile-time"); } }; @@ -587,9 +586,11 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { let typ = self.concretize_type(&wire_decl.typ_expr)?; Ok(if wire_decl.identifier_type == IdentifierType::Generative { - let value = if let DeclarationPortInfo::GenerativeInput(template_id) = wire_decl.is_port { + let value = if let DeclarationKind::GenerativeInput(template_id) = wire_decl.decl_kind { + // Only for template arguments, we must initialize their value to the value they've been assigned in the template instantiation self.template_args[template_id].unwrap_value().clone() } else { + // Empty initial value typ.get_initial_typed_val() }; SubModuleOrWire::CompileTimeValue(value) @@ -672,13 +673,13 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { Instruction::Declaration(wire_decl) => { self.instantiate_declaration(wire_decl, original_instruction)? } - Instruction::Wire(w) => match w.typ.domain { + Instruction::Expression(expr) => match expr.typ.domain { DomainType::Generative => { - let value_computed = self.compute_compile_time(w)?; + let value_computed = self.compute_compile_time(expr)?; SubModuleOrWire::CompileTimeValue(value_computed) } DomainType::Physical(domain) => { - let wire_found = self.wire_to_real_wire(w, original_instruction, domain)?; + let wire_found = self.expression_to_real_wire(expr, original_instruction, domain)?; SubModuleOrWire::Wire(wire_found) } DomainType::DomainVariable(_) => unreachable!("Domain variables have been eliminated by type checking") @@ -728,8 +729,8 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { Instruction::IfStatement(stm) => { let then_range = FlatIDRange::new(stm.then_start, stm.then_end_else_start); let else_range = FlatIDRange::new(stm.then_end_else_start, stm.else_end); - let if_condition_wire = self.md.link_info.instructions[stm.condition].unwrap_wire(); - match if_condition_wire.typ.domain { + let if_condition_expr = self.md.link_info.instructions[stm.condition].unwrap_expression(); + match if_condition_expr.typ.domain { DomainType::Generative => { let condition_val = self.generation_state.get_generation_value(stm.condition)?; @@ -771,8 +772,8 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { .unwrap_integer() .clone(); if start_val > end_val { - let start_flat = &self.md.link_info.instructions[stm.start].unwrap_wire(); - let end_flat = &self.md.link_info.instructions[stm.end].unwrap_wire(); + let start_flat = &self.md.link_info.instructions[stm.start].unwrap_expression(); + let end_flat = &self.md.link_info.instructions[stm.end].unwrap_expression(); return Err(( Span::new_overarching(start_flat.span, end_flat.span), format!("for loop range end is before begin: {start_val}:{end_val}"), diff --git a/src/instantiation/latency_algorithm.rs b/src/instantiation/latency_algorithm.rs index d4ca08a..ee8c1f2 100644 --- a/src/instantiation/latency_algorithm.rs +++ b/src/instantiation/latency_algorithm.rs @@ -2,6 +2,9 @@ use crate::config::config; use super::list_of_lists::ListOfLists; +/// A wire for which a latency has been specified. +/// +/// Provided as a list to [solve_latencies]. #[derive(Debug, Clone, Copy)] pub struct SpecifiedLatency { pub wire: usize, @@ -22,6 +25,7 @@ pub enum LatencyCountingError { }, } +/// A graph connection from (resp to) another wire, which specifies the minimal (resp maximal) difference in latency between them. #[derive(Debug, Clone, Copy)] pub struct FanInOut { pub other: usize, diff --git a/src/instantiation/latency_count.rs b/src/instantiation/latency_count.rs index 035356f..71ad336 100644 --- a/src/instantiation/latency_count.rs +++ b/src/instantiation/latency_count.rs @@ -71,7 +71,7 @@ fn filter_unique_write_flats<'w>( let mut result: Vec<&'w crate::flattening::Write> = Vec::new(); for w in writes { if let Instruction::Write(original_write) = - &instructions[w.mux_input.from.original_connection] + &instructions[w.mux_input.original_connection] { if !result .iter() @@ -107,10 +107,10 @@ impl RealWireDataSource { sources, } => { for s in sources { - f(s.from.from, s.from.num_regs); - RealWirePathElem::for_each_wire_in_path(&s.to_path, |w| f(w, s.from.num_regs)); - for elem in s.from.condition.iter() { - f(elem.condition_wire, s.from.num_regs); + f(s.from, s.num_regs); + RealWirePathElem::for_each_wire_in_path(&s.to_path, |w| f(w, s.num_regs)); + for elem in s.condition.iter() { + f(elem.condition_wire, s.num_regs); } } } @@ -390,7 +390,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { predecessor_found = true; } }; - predecessor_adder(s.from.from); + predecessor_adder(s.from); RealWirePathElem::for_each_wire_in_path(&s.to_path, predecessor_adder); if predecessor_found { connection_list.push(PathMuxSource { @@ -467,7 +467,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { for port in bad_ports { let port_decl = self.md.link_info.instructions [self.wires[latency_node_meanings[port.0]].original_instruction] - .unwrap_wire_declaration(); + .unwrap_declaration(); self.errors.error(port_decl.name_span, format!("Cannot determine port latency. Options are {} and {}\nTry specifying an explicit latency or rework the module to remove this ambiguity", port.1, port.2)); } } @@ -477,11 +477,11 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { let end_wire = &self.wires[latency_node_meanings[conflict_path.last().unwrap().wire]]; let start_decl = - self.md.link_info.instructions[start_wire.original_instruction].unwrap_wire_declaration(); + self.md.link_info.instructions[start_wire.original_instruction].unwrap_declaration(); let end_decl = - self.md.link_info.instructions[end_wire.original_instruction].unwrap_wire_declaration(); + self.md.link_info.instructions[end_wire.original_instruction].unwrap_declaration(); let end_latency_decl = - self.md.link_info.instructions[end_decl.latency_specifier.unwrap()].unwrap_wire(); + self.md.link_info.instructions[end_decl.latency_specifier.unwrap()].unwrap_expression(); let writes_involved = self.gather_all_mux_inputs(latency_node_meanings, &conflict_path); diff --git a/src/instantiation/list_of_lists.rs b/src/instantiation/list_of_lists.rs index 7f2f92d..295c6a4 100644 --- a/src/instantiation/list_of_lists.rs +++ b/src/instantiation/list_of_lists.rs @@ -3,6 +3,7 @@ use std::{ ops::{Index, IndexMut}, }; +/// Basically `Vec>`, but reduces pointer chasing by laying the nested vectors all out sequentially. Read-only. #[derive(Debug, Clone)] pub struct ListOfLists { buf: Vec, diff --git a/src/instantiation/mod.rs b/src/instantiation/mod.rs index bbb3a9d..765d2de 100644 --- a/src/instantiation/mod.rs +++ b/src/instantiation/mod.rs @@ -31,14 +31,6 @@ use self::latency_algorithm::SpecifiedLatency; // Temporary value before proper latency is given pub const CALCULATE_LATENCY_LATER: i64 = i64::MIN; -#[derive(Debug)] -pub struct ConnectFrom { - pub num_regs: i64, - pub from: WireID, - pub condition: Box<[ConditionStackElem]>, - pub original_connection: FlatID, -} - #[derive(Debug, Clone)] pub enum RealWirePathElem { ArrayAccess { span: BracketSpan, idx_wire: WireID }, @@ -56,12 +48,21 @@ impl RealWirePathElem { } } +/// One arm of a multiplexer. Each arm has an attached condition that is also stored here. +/// +/// See [RealWireDataSource::Multiplexer] #[derive(Debug)] pub struct MultiplexerSource { pub to_path: Vec, - pub from: ConnectFrom, + pub num_regs: i64, + pub from: WireID, + pub condition: Box<[ConditionStackElem]>, + pub original_connection: FlatID, } +/// Where a [RealWire] gets its data, be it an operator, read-only value, constant, etc. +/// +/// This is the post-instantiation equivalent of [crate::flattening::ExpressionSource] #[derive(Debug)] pub enum RealWireDataSource { ReadOnly, @@ -87,6 +88,9 @@ pub enum RealWireDataSource { }, } +/// An actual instantiated wire of an [InstantiatedModule] (See [InstantiatedModule::wires]) +/// +/// It can have a latency count and domain. All wires have a name, either the name they were given by the user, or a generated name like _1, _13 #[derive(Debug)] pub struct RealWire { pub source: RealWireDataSource, @@ -101,17 +105,25 @@ pub struct RealWire { pub absolute_latency: i64, } +/// See [SubModule] +/// +/// This represents a port of such a submodule #[derive(Debug)] -pub struct UsedPort { +pub struct SubModulePort { pub maps_to_wire: WireID, pub name_refs: Vec, } +/// An actual instantiated submodule of an [InstantiatedModule] (See [InstantiatedModule::submodules]) +/// +/// All submodules have a name, either the name they were given by the user, or a generated name like _1, _13 +/// +/// When generating RTL code, one submodule object generates a single submodule instantiation #[derive(Debug)] pub struct SubModule { pub original_instruction: FlatID, pub instance: OnceCell>, - pub port_map: FlatAlloc, PortIDMarker>, + pub port_map: FlatAlloc, PortIDMarker>, pub interface_call_sites: FlatAlloc, InterfaceIDMarker>, pub name: String, pub module_uuid: ModuleUUID, diff --git a/src/value.rs b/src/value.rs index f4a3703..8e4ba18 100644 --- a/src/value.rs +++ b/src/value.rs @@ -159,6 +159,10 @@ pub fn compute_binary_op(left: &TypedValue, op: BinaryOperator, right: &TypedVal } } +/// A value with an attached [ConcreteType]. +/// +/// TODO: Because we now have Hindley-Milner type inference, the need for adding types to values seems to have gone away +/// IE, the reason we added types in the first place was because we couldn't figure out the type of an empty array, but with HM that's no problem #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct TypedValue { pub value: Value,