diff --git a/src/alloc.rs b/src/alloc.rs index c151275..2c72c75 100644 --- a/src/alloc.rs +++ b/src/alloc.rs @@ -7,8 +7,12 @@ use std::{ ops::{Index, IndexMut}, }; -// TODO add custom niche for more efficient Options, wait until custom niches are stabilized (https://internals.rust-lang.org/t/nonmaxusize-and-niche-value-optimisation/19661) -// Maybe use NonZeroUsize (https://doc.rust-lang.org/std/num/struct.NonZeroUsize.html) +/// UUIDs are type-safe integers. They are used for [FlatAlloc] and [ArenaAllocator] +/// +/// They don't support arithmetic, as they're just meant to represent pointers. +/// +/// TODO add custom niche for more efficient Options, wait until custom niches are stabilized (https://internals.rust-lang.org/t/nonmaxusize-and-niche-value-optimisation/19661) +/// Maybe use NonZeroUsize (https://doc.rust-lang.org/std/num/struct.NonZeroUsize.html) pub struct UUID(usize, PhantomData); impl Clone for UUID { @@ -29,6 +33,7 @@ impl Hash for UUID { } } +/// See [UUID] pub trait UUIDMarker { const DISPLAY_NAME: &'static str; } diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 960944a..4481acb 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -9,6 +9,7 @@ use crate::{InstantiatedModule, Linker, Module}; use std::{fs::{self, File}, io::Write, path::PathBuf, rc::Rc}; +/// Implemented for SystemVerilog [self::system_verilog] or VHDL [self::vhdl] pub trait CodeGenBackend { fn file_extension(&self) -> &str; fn output_dir_name(&self) -> &str; diff --git a/src/compiler_top.rs b/src/compiler_top.rs index 948717f..2cd599b 100644 --- a/src/compiler_top.rs +++ b/src/compiler_top.rs @@ -19,6 +19,7 @@ use crate::flattening::{ const STD_LIB_PATH: &str = env!("SUS_COMPILER_STD_LIB_PATH"); +/// Any extra operations that should happen when files are added or removed from the linker. Such as caching line offsets. pub trait LinkerExtraFileInfoManager { /// This is there to give an acceptable identifier that can be printed fn convert_filename(&self, path : &PathBuf) -> String { diff --git a/src/dev_aid/lsp/tree_walk.rs b/src/dev_aid/lsp/tree_walk.rs index 4c86c4b..6889a3b 100644 --- a/src/dev_aid/lsp/tree_walk.rs +++ b/src/dev_aid/lsp/tree_walk.rs @@ -10,6 +10,7 @@ use crate::typing::template::{ ParameterKind, TypeParameterKind, }; +/// See [LocationInfo] #[derive(Clone, Copy, Debug)] pub enum InModule<'linker> { NamedLocal(&'linker Declaration), @@ -17,6 +18,7 @@ pub enum InModule<'linker> { Temporary(&'linker Expression), } +/// Information about an object in the source code. Used for hovering, completions, syntax highlighting etc. #[derive(Clone, Copy, Debug)] pub enum LocationInfo<'linker> { InModule(ModuleUUID, &'linker Module, FlatID, InModule<'linker>), diff --git a/src/errors.rs b/src/errors.rs index 0a56bec..659f702 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -254,6 +254,7 @@ pub trait ErrorInfoObject { fn make_info(&self, file: FileUUID) -> ErrorInfo; } +/// This represents objects that can be given as info to an error in a straight-forward way. pub trait FileKnowingErrorInfoObject { fn make_global_info( &self, diff --git a/src/flattening/initialization.rs b/src/flattening/initialization.rs index 2effe46..7c3e2f9 100644 --- a/src/flattening/initialization.rs +++ b/src/flattening/initialization.rs @@ -265,6 +265,13 @@ pub fn gather_initial_file_data(mut builder: FileBuilder) { ); } + +enum GlobalObjectKind { + Module, + Const, + Struct +} + fn initialize_global_object(builder: &mut FileBuilder, parsing_errors: ErrorCollector, span: Span, cursor: &mut Cursor) { let is_extern = match cursor.optional_field(field!("extern_marker")).then(|| cursor.kind()) { None => IsExtern::Normal, diff --git a/src/flattening/mod.rs b/src/flattening/mod.rs index 4abc91d..79a8034 100644 --- a/src/flattening/mod.rs +++ b/src/flattening/mod.rs @@ -27,13 +27,6 @@ use crate::typing::{ template::GlobalReference, }; -#[derive(Debug)] -pub enum GlobalObjectKind { - Module, - Const, - Struct -} - /// Modules are compiled in 4 stages. All modules must pass through each stage before advancing to the next stage. /// /// 1. Initialization: initial name resolution and port discovery. The Module objects themselves are constructed. @@ -309,6 +302,8 @@ impl Interface { } /// An element in a [WireReference] path. Could be array accesses, slice accesses, field accesses, etc +/// +/// When executing, this turns into [crate::instantiation::RealWirePathElem] #[derive(Debug, Clone, Copy)] pub enum WireReferencePathElement { ArrayAccess { diff --git a/src/instantiation/latency_algorithm.rs b/src/instantiation/latency_algorithm.rs index ee8c1f2..99f1894 100644 --- a/src/instantiation/latency_algorithm.rs +++ b/src/instantiation/latency_algorithm.rs @@ -11,6 +11,7 @@ pub struct SpecifiedLatency { pub latency: i64, } +/// All the ways [solve_latencies] can go wrong #[derive(Debug)] pub enum LatencyCountingError { ConflictingSpecifiedLatencies { @@ -60,8 +61,9 @@ struct LatencyStackElem<'d> { remaining_fanout: std::slice::Iter<'d, FanInOut>, } -// Attempt 3 for Latency Counting -// TODO make this only take up 8 bytes with bitfield +/// The node for the latency-counting graph. See [solve_latencies] +/// +/// TODO make this only take up 8 bytes with bitfield #[derive(Clone, Copy)] struct LatencyNode { abs_lat: i64, diff --git a/src/instantiation/mod.rs b/src/instantiation/mod.rs index 3dfeb8a..e7f1e47 100644 --- a/src/instantiation/mod.rs +++ b/src/instantiation/mod.rs @@ -31,6 +31,9 @@ use self::latency_algorithm::SpecifiedLatency; // Temporary value before proper latency is given pub const CALCULATE_LATENCY_LATER: i64 = i64::MIN; +/// See [MultiplexerSource] +/// +/// This is the post-instantiation equivalent of [crate::flattening::WireReferencePathElement] #[derive(Debug, Clone)] pub enum RealWirePathElem { ArrayAccess { span: BracketSpan, idx_wire: WireID }, diff --git a/src/linker/mod.rs b/src/linker/mod.rs index 19c59c5..84dbb3a 100644 --- a/src/linker/mod.rs +++ b/src/linker/mod.rs @@ -58,16 +58,23 @@ impl Documentation { } } +/// [Module], [StructType], or [NamedConstant] annotation that specifies exceptions to code generation. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum IsExtern { + /// Code is generated for this through the regular channel (See [crate::codegen]) + /// /// ```sus /// module md {} /// ``` Normal, + /// Modules that are provided externally, and thus no code should be generated for these + /// /// ```sus /// extern module md {} /// ``` Extern, + /// Builtins, like escape hatches for Latency Counting & domains + /// /// ```sus /// __builtin__ module md {} /// ``` diff --git a/src/to_string.rs b/src/to_string.rs index eac5fbd..4eca7a2 100644 --- a/src/to_string.rs +++ b/src/to_string.rs @@ -24,6 +24,7 @@ pub fn map_to_type_names(parameters: &Parameters) -> FlatAlloc &str; } diff --git a/src/typing/abstract_type.rs b/src/typing/abstract_type.rs index a956b70..8a1a86b 100644 --- a/src/typing/abstract_type.rs +++ b/src/typing/abstract_type.rs @@ -9,18 +9,28 @@ use crate::flattening::{BinaryOperator, StructType, TypingAllocator, UnaryOperat use crate::linker::get_builtin_type; use crate::to_string::map_to_type_names; -/// This contains only the information that can be easily type-checked. +/// This contains only the information that can be type-checked before template instantiation. /// /// Its most important components are the names and structure of types. /// /// What isn't included are the parameters of types. So Array Sizes for example. +/// +/// This is such that useful information can still be given for modules that haven't been instantiated. +/// +/// Not to be confused with [WrittenType], which is the in-source text representation. +/// +/// Not to be confused with [crate::typing::concrete_type::ConcreteType], which is the +/// post-instantiation type. +/// +/// [AbstractType]s don't actually get converted to [crate::typing::concrete_type::ConcreteType]s. +/// Instead [crate::typing::concrete_type::ConcreteType] gets created from [WrittenType] directly. #[derive(Debug, Clone)] pub enum AbstractType { Template(TemplateID), Named(TypeUUID), Array(Box), /// Referencing [AbstractType::Unknown] is a strong code smell. - /// It is likely you should use [TypeSubstitutor::unify] instead + /// It is likely you should use [TypeSubstitutor::unify_must_succeed] or [TypeSubstitutor::unify_report_error] instead /// /// It should only occur in creation `AbstractType::Unknown(self.type_substitutor.alloc())` Unknown(TypeVariableID), @@ -29,6 +39,15 @@ pub enum AbstractType { pub const BOOL_TYPE: AbstractType = AbstractType::Named(get_builtin_type("bool")); pub const INT_TYPE: AbstractType = AbstractType::Named(get_builtin_type("int")); +/// These represent (clock) domains. While clock domains are included under this umbrella, domains can use the same clock. +/// The use case for non-clock-domains is to separate Latency Counting domains. So different pipelines where it doesn't +/// necessarily make sense that their values are related by a fixed number of clock cycles. +/// +/// Domains are resolved pre-instantiation, because dynamic domain merging doesn't seem like a valuable use case. +/// +/// As a convenience, we make [DomainType::Generative] a special case for a domain. +/// +/// The fun thing is that we can now use this domain info for syntax highlighting, giving wires in different domains a different color. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum DomainType { /// Generative conflicts with nothing @@ -41,7 +60,7 @@ pub enum DomainType { /// They always point to non-generative domains. /// /// Referencing [DomainType::Unknown] is a strong code smell. - /// It is likely you should use [TypeSubstitutor::unify] instead + /// It is likely you should use [TypeSubstitutor::unify_must_succeed] or [TypeSubstitutor::unify_report_error] instead /// /// It should only occur in creation `DomainType::Unknown(self.domain_substitutor.alloc())` Unknown(DomainVariableID) diff --git a/src/typing/concrete_type.rs b/src/typing/concrete_type.rs index bb03f55..a6504ed 100644 --- a/src/typing/concrete_type.rs +++ b/src/typing/concrete_type.rs @@ -11,13 +11,21 @@ use super::type_inference::ConcreteTypeVariableID; pub const BOOL_CONCRETE_TYPE: ConcreteType = ConcreteType::Named(get_builtin_type("bool")); pub const INT_CONCRETE_TYPE: ConcreteType = ConcreteType::Named(get_builtin_type("int")); +/// A post-instantiation type. These fully define what wires should be generated for a given object. +/// So as opposed to [crate::typing::abstract_type::AbstractType], type parameters are filled out with concrete values. +/// +/// Examples: `bool[3]`, `int #(MAX: 20)` +/// +/// Not to be confused with [crate::typing::abstract_type::AbstractType] which represents pre-instantiation types, +/// or [crate::flattening::WrittenType] which represents the textual in-editor data. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum ConcreteType { Named(TypeUUID), Value(Value), Array(Box<(ConcreteType, ConcreteType)>), /// Referencing [ConcreteType::Unknown] is a strong code smell. - /// It is likely you should use [crate::typing::type_inference::TypeSubstitutor::unify] instead + /// It is likely you should use [crate::typing::type_inference::TypeSubstitutor::unify_must_succeed] + /// or [crate::typing::type_inference::TypeSubstitutor::unify_report_error] instead /// /// It should only occur in creation `ConcreteType::Unknown(self.type_substitutor.alloc())` Unknown(ConcreteTypeVariableID) diff --git a/src/typing/template.rs b/src/typing/template.rs index 727fb65..be2737d 100644 --- a/src/typing/template.rs +++ b/src/typing/template.rs @@ -54,6 +54,8 @@ pub struct GenerativeParameterKind { pub struct TypeParameterKind {} /// See [Parameter] +/// +/// Must match the [TemplateArgKind] that is passed #[derive(Debug)] pub enum ParameterKind { Type(TypeParameterKind), @@ -91,6 +93,9 @@ pub struct TemplateArg { pub kind: TemplateArgKind, } +/// See [TemplateArg] +/// +/// The argument kind passed to [ParameterKind], which it must match #[derive(Debug)] pub enum TemplateArgKind { Type(WrittenType), diff --git a/src/typing/type_inference.rs b/src/typing/type_inference.rs index 92c1e76..a12a0fb 100644 --- a/src/typing/type_inference.rs +++ b/src/typing/type_inference.rs @@ -178,6 +178,15 @@ impl, VariableIDMarker: UUIDMarker> Drop } } +/// See [HindleyMilner] +/// +/// `TypeFuncIdent` is a value object, that is a "terminal". Basically, it's an atom that can either be equal or not. +/// +/// Usually this is type names: `int` `bool`, or "array of" without the containing type. +/// +/// Basically, when unifying, `int` isn't equal to "array of", and thus a type error is generated +/// +/// This enum itself then is either such a terminal, or a type variable that can be unified (IE substituted) #[derive(Debug, Clone, Copy)] pub enum HindleyMilnerInfo { /// Just a marker. Use [HindleyMilner::unify_all_args] @@ -185,6 +194,13 @@ pub enum HindleyMilnerInfo { TypeVar(UUID) } +/// Implements Hindley-Milner type unification for various types in the SUS language +/// +/// Unification is roughly based on this video: https://www.youtube.com/watch?v=KNbRLTLniZI +/// The other HM videos are also highly recommended to understand this +/// +/// Though this implementation does eager unification as much as possible, while unifications that cannot +/// be performed eagerly are handled by [DelayedConstraintsList]. pub trait HindleyMilner : Sized { type TypeFuncIdent<'slf> : Eq where Self : 'slf; @@ -203,7 +219,7 @@ pub trait HindleyMilner : Sized { fn fully_substitute(&mut self, substitutor: &TypeSubstitutor) -> bool; } - +/// [HindleyMilnerInfo] `TypeFuncIdent` for [AbstractType] #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum AbstractTypeHMInfo { Template(TemplateID), @@ -276,6 +292,7 @@ impl HindleyMilner for DomainType { } +/// [HindleyMilnerInfo] `TypeFuncIdent` for [ConcreteType] #[derive(Debug, Clone, PartialEq, Eq)] pub enum ConcreteTypeHMInfo<'slf> { Named(TypeUUID), @@ -326,14 +343,20 @@ impl HindleyMilner for ConcreteType { } } - +/// See [DelayedConstraintsList::resolve_delayed_constraints] #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum DelayedConstraintStatus { + /// The constraint can be removed Resolved, + /// Progress was made, (potentially enabling other parts to continue), but the constraint cannot be removed Progress, + /// No progress was made, if all constraints return [DelayedConstraintStatus::NoProgress] then type resolution deadlocked and cannot finish. NoProgress } +/// Implement this for any typing constraints that can't be resolved immediately. +/// +/// See [DelayedConstraintsList] pub trait DelayedConstraint { fn try_apply(&mut self, shared_object : &mut T) -> DelayedConstraintStatus; fn report_could_not_resolve_error(&self, shared_object : &T); diff --git a/src/value.rs b/src/value.rs index f3134b8..0e9ff8f 100644 --- a/src/value.rs +++ b/src/value.rs @@ -9,11 +9,15 @@ use crate::typing::{ type_inference::{ConcreteTypeVariableIDMarker, TypeSubstitutor} }; +/// Top type for any kind of compiletime value while executing. +/// +/// These are used during execution ([crate::instantiation::execute]) #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum Value { Bool(bool), Integer(BigInt), Array(Box<[Value]>), + /// The initial [Value] a variable has, before it's been set. (translates to `'x` don't care) Unset, Error, }