diff --git a/multiply_add.sus b/multiply_add.sus index 47ef9da..e75e847 100644 --- a/multiply_add.sus +++ b/multiply_add.sus @@ -110,7 +110,7 @@ module packer : T[256] data /* v _ _ _ */ -> T[64] out { /* v v v v */ } -module multiply_add : i32 a, i32 b, i32 c -> i32 result, double double_result { +module multiply_add_old : i32 a, i32 b, i32 c -> i32 result, double double_result { i32 tmp = a * b; reg result = tmp + c; reg double_result = cvt_to_double(result); @@ -200,14 +200,35 @@ module b: HandShake hs -> { +module multiply_add : + int a, + int b, + int c + -> int total { + reg int tmp = a * b; + total = tmp + c; +} + +//timeline (v, true -> /) .. (v, false -> v)* +module blur2 : + int data, + bool first + -> int blurred { + + state int prev; + if !first { + blurred = data + prev; + } + prev = data; +} module Tree_Multiply : int[4] values -> int total { - int a = values[0] * values[1]; + reg int a = values[0] * values[1]; int b = values[2] * values[3]; - reg total = a * b; + total = a * b; } @@ -221,8 +242,7 @@ module Accumulator : int term, bool done -> int total { int new_tot = tot + term; if done { total = new_tot; - tot = 0; - //finish; // packet is hereby finished. + tot = 0; // Must restore initial conditions } else { tot = new_tot; } @@ -266,3 +286,63 @@ module Unpack4 : int[4] packed -> int out_stream { //finish; // packet is hereby finished. } } + + + + +//timeline (bs -> /, true) | (bs -> v, false) +module first_bit_idx_6 : bool[6] bits -> int first, bool all_zeros { + if bits[0] { + first = 0; + all_zeros = false; + } else if bits[1] { + first = 1; + all_zeros = false; + } else if bits[2] { + first = 2; + all_zeros = false; + } else if bits[3] { + first = 3; + all_zeros = false; + } else if bits[4] { + first = 4; + all_zeros = false; + } else if bits[5] { + first = 5; + all_zeros = false; + } else { + all_zeros = true; + } +} + +module first_bit_idx_24 : bool[24] bits -> int first { + int[4] offsets; + bool[4] was_nonzero; + + for i in 0..4 { + offsets[i], was_nonzero[i] = first_bit_idx_6(bits[i*6+:6]); + } +} + +module permute : bool[128] mbf, int selected_permutation -> bool[128] permuted_mbf { + // TODO +} + +//timeline (X, [false;24], true -> /, false) | (X, vs, true -> X, true) .. (/, /, false -> X, true)* +module permute24 : bool[128] mbf, bool[24] valid_permutes, bool start -> bool[128] permuted_out, bool permuted_out_valid { + state bool[128] stored_mbf; + state bool[24] stored_valid_permutes = 000000000000000000000000; + + + bool[24] permutes_to_keep; + permutes_to_keep[0] = false; + for i in 1..24 { + permutes_to_keep[i] = permutes_to_keep[i-1] | stored_valid_permutes[i-1]; + } + + int current_permutation_idx = first_bit_idx_24(permutes_to_keep); + + stored_valid_permutes = stored_valid_permutes & permutes_to_keep; + + permuted_out = permute(stored_mbf, current_permutation_idx); +} diff --git a/resetNormalizer.sus b/resetNormalizer.sus index 1859a57..3a4146d 100644 --- a/resetNormalizer.sus +++ b/resetNormalizer.sus @@ -1,6 +1,4 @@ -module hello_from_the_other_side : int a -> int result { - if true { - result = a; - } +module hello_from_the_other_side : int[3] a -> int result { + result = a[2]; } diff --git a/src/arena_alloc.rs b/src/arena_alloc.rs index f037499..7ad0024 100644 --- a/src/arena_alloc.rs +++ b/src/arena_alloc.rs @@ -1,5 +1,7 @@ use std::{ops::{IndexMut, Index}, marker::PhantomData, iter::Enumerate, fmt}; +use crate::block_vector::{BlockVec, BlockVecIterMut, BlockVecIter}; + #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct UUID(usize, PhantomData); @@ -24,8 +26,10 @@ impl Default for UUID { } } +const INVALID_UUID_VALUE : usize = usize::MAX; + impl UUID { - pub const INVALID : Self = UUID(usize::MAX, PhantomData); + pub const INVALID : Self = UUID(INVALID_UUID_VALUE, PhantomData); pub const fn from_hidden_value(v : usize) -> Self { UUID(v, PhantomData) @@ -93,6 +97,7 @@ impl Index> for ArenaAllocator) -> &Self::Output { + assert!(uuid != INVALID_UUID_VALUE, "Invalid UUID passed to index"); assert!(self.data[uuid].is_some()); self.data[uuid].as_ref().unwrap() } @@ -100,6 +105,7 @@ impl Index> for ArenaAllocator IndexMut> for ArenaAllocator { fn index_mut(&mut self, UUID(uuid, _): UUID) -> &mut Self::Output { + assert!(uuid != INVALID_UUID_VALUE, "Invalid UUID passed to index_mut"); assert!(self.data[uuid].is_some()); self.data[uuid].as_mut().unwrap() } @@ -202,12 +208,14 @@ impl Index> for ArenaVector) -> &Self::Output { + assert!(uuid != INVALID_UUID_VALUE, "Invalid UUID passed to index"); self.data[uuid].as_ref().unwrap() } } impl IndexMut> for ArenaVector { fn index_mut(&mut self, UUID(uuid, _): UUID) -> &mut Self::Output { + assert!(uuid != INVALID_UUID_VALUE, "Invalid UUID passed to index_mut"); self.data[uuid].as_mut().unwrap() } } @@ -234,18 +242,17 @@ impl<'a, T, IndexMarker : UUIDMarker> IntoIterator for &'a mut ArenaVector { - data : Vec, + data : BlockVec, _ph : PhantomData } impl ListAllocator { pub fn new() -> Self { - Self{data : Vec::new(), _ph : PhantomData} + Self{data : BlockVec::new(), _ph : PhantomData} } - pub fn alloc(&mut self, v : T) -> UUID { - let uuid = UUID(self.data.len(), PhantomData); - self.data.push(v); - uuid + // Allocation is const because it doesn't invalidate existing references + pub fn alloc(&self, v : T) -> UUID { + UUID(self.data.alloc(v), PhantomData) } pub fn iter<'a>(&'a self) -> ListAllocIterator<'a, T, IndexMarker> { self.into_iter() @@ -253,28 +260,32 @@ impl ListAllocator { pub fn iter_mut<'a>(&'a mut self) -> ListAllocIteratorMut<'a, T, IndexMarker> { self.into_iter() } - pub fn map, &T) -> OutT>(&self, mut f : F) -> ListAllocator { - let data = self.iter().map(|(a, v)| f(a, v)).collect(); - ListAllocator{data, _ph : PhantomData} - } } impl Index> for ListAllocator { type Output = T; fn index(&self, UUID(uuid, _): UUID) -> &Self::Output { + assert!(uuid != INVALID_UUID_VALUE, "Invalid UUID passed to index"); &self.data[uuid] } } impl IndexMut> for ListAllocator { fn index_mut(&mut self, UUID(uuid, _): UUID) -> &mut Self::Output { + assert!(uuid != INVALID_UUID_VALUE, "Invalid UUID passed to index_mut"); &mut self.data[uuid] } } +impl FromIterator for ListAllocator { + fn from_iter>(iter: Iter) -> Self { + Self { data: BlockVec::from_iter(iter), _ph: PhantomData } + } +} + pub struct ListAllocIterator<'a, T, IndexMarker> { - it: Enumerate>, + it: Enumerate>, _ph : PhantomData } @@ -294,7 +305,7 @@ impl<'a, T, IndexMarker : UUIDMarker> Iterator for ListAllocIterator<'a, T, Inde } pub struct ListAllocIteratorMut<'a, T, IndexMarker> { - it: Enumerate>, + it: Enumerate>, _ph : PhantomData } diff --git a/src/ast.rs b/src/ast.rs index 0f5763f..857045b 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1,7 +1,7 @@ use num::bigint::BigUint; -use crate::{tokenizer::{TokenTypeIdx, get_token_type_name}, linker::{NamedUUID, FileUUID}, flattening::{FlattenedModule, FlatIDMarker, FlatID, FlattenedInterface}, arena_alloc::ListAllocator}; +use crate::{tokenizer::{TokenTypeIdx, get_token_type_name}, linker::{NamedUUID, FileUUID}, flattening::{FlattenedModule, FlattenedInterface}, arena_alloc::{ListAllocator, UUIDMarker, UUID}, instantiation::InstantiationList}; use core::ops::Range; use std::fmt::Display; @@ -9,6 +9,13 @@ use std::fmt::Display; #[derive(Clone,Copy,Debug,PartialEq,Eq)] pub struct Span(pub usize, pub usize); + +#[derive(Debug,Clone,Copy,PartialEq,Eq,Hash)] +pub struct DeclIDMarker; +impl UUIDMarker for DeclIDMarker {const DISPLAY_NAME : &'static str = "obj_";} +pub type DeclID = UUID; + + impl Span { pub fn to_range(&self, tokens : &[Range]) -> Range { let min = tokens[self.0].start.clone(); @@ -43,7 +50,7 @@ impl From for Span { #[derive(Debug, Clone, Copy)] pub enum LocalOrGlobal { - Local(FlatID), + Local(DeclID), Global(usize) } @@ -87,7 +94,7 @@ pub enum Expression { Constant(Value), UnaryOp(Box<(Operator, usize/*Operator token */, SpanExpression)>), BinOp(Box<(SpanExpression, Operator, usize/*Operator token */, SpanExpression)>), - Array(Box<(SpanExpression, SpanExpression)>), // first[second] + Array(Box<(SpanExpression, SpanExpression, Span/*Brackets */)>), // first[second] FuncCall(Vec) // first(second, third, ...) } @@ -103,8 +110,8 @@ pub type SpanStatement = (Statement, Span); #[derive(Debug)] pub enum AssignableExpression { - Named{local_idx : FlatID}, - ArrayIndex(Box<(SpanAssignableExpression, SpanExpression)>) + Named{local_idx : DeclID}, + ArrayIndex(Box<(SpanAssignableExpression, SpanExpression, Span/* Brackets */)>) } #[derive(Debug)] @@ -120,7 +127,7 @@ pub struct CodeBlock { #[derive(Debug)] pub enum Statement { - Declaration(FlatID), + Declaration(DeclID), Assign{to : Vec, eq_sign_position : Option, expr : SpanExpression}, // num_regs v = expr; If{condition : SpanExpression, then : CodeBlock, els : Option}, Block(CodeBlock), @@ -141,11 +148,13 @@ pub struct LinkInfo { pub struct Module { pub link_info : LinkInfo, - pub declarations : ListAllocator, + pub declarations : ListAllocator, pub code : CodeBlock, pub interface : FlattenedInterface, - pub flattened : FlattenedModule + pub flattened : FlattenedModule, + + pub instantiations : InstantiationList } #[derive(Debug,Clone,Copy)] @@ -184,7 +193,7 @@ impl IterIdentifiers for SpanExpression { } } Expression::Array(b) => { - let (array, idx) = &**b; + let (array, idx, bracket_span) = &**b; array.for_each_value(func); idx.for_each_value(func); } @@ -201,7 +210,7 @@ impl IterIdentifiers for SpanAssignableExpression { func(LocalOrGlobal::Local(*id), span.0); } AssignableExpression::ArrayIndex(b) => { - let (array, idx) = &**b; + let (array, idx, bracket_span) = &**b; array.for_each_value(func); idx.for_each_value(func); } diff --git a/src/block_vector.rs b/src/block_vector.rs index 1a9b9e7..a1a841c 100644 --- a/src/block_vector.rs +++ b/src/block_vector.rs @@ -2,7 +2,15 @@ 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 */ +/* + 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(Debug,Default)] pub struct BlockVec { blocks : UnsafeCell; BLOCK_SIZE]>>>, @@ -14,11 +22,6 @@ impl BlockVec { Self{blocks : UnsafeCell::new(Vec::new()), length : Cell::new(0)} } - /* - Critically, 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. - Because it would conflict with this function, this class does not provide an immutable iterator. - */ pub fn alloc(&self, obj : T) -> usize { let b = self.blocks.get(); @@ -46,6 +49,14 @@ impl BlockVec { allocated_id } + + pub fn iter<'s>(&'s self) -> BlockVecIter<'s, T, BLOCK_SIZE> { + self.into_iter() + } + + pub fn iter_mut<'s>(&'s mut self) -> BlockVecIterMut<'s, T, BLOCK_SIZE> { + self.into_iter() + } } impl Drop for BlockVec { @@ -98,7 +109,41 @@ impl IndexMut for BlockVec { } } -pub struct BlockVecIterMut<'bv, T, const BLOCK_SIZE : usize> { + +pub struct BlockVecIter<'bv, T, const BLOCK_SIZE : usize = 64> { + block_vec : &'bv BlockVec, + cur_idx : usize +} + +impl<'bv, T, const BLOCK_SIZE : usize> Iterator for BlockVecIter<'bv, T, BLOCK_SIZE> { + type Item = &'bv T; + + fn next(&mut self) -> Option<&'bv T> { + if self.cur_idx < self.block_vec.length.get() { + let selected_idx = self.cur_idx; + self.cur_idx += 1; + + Some(&self.block_vec[selected_idx]) + } else { + return None; + } + } +} + +impl<'bv, T, const BLOCK_SIZE : usize> IntoIterator for &'bv BlockVec { + type Item = &'bv T; + + type IntoIter = BlockVecIter<'bv, T, BLOCK_SIZE>; + + fn into_iter(self) -> Self::IntoIter { + BlockVecIter{ + block_vec : self, + cur_idx : 0 + } + } +} + +pub struct BlockVecIterMut<'bv, T, const BLOCK_SIZE : usize = 64> { block_vec_iter : <&'bv mut Vec; BLOCK_SIZE]>> as IntoIterator>::IntoIter, current_block : std::slice::IterMut<'bv, MaybeUninit>, remaining : usize @@ -139,7 +184,7 @@ impl<'bv, T, const BLOCK_SIZE : usize> IntoIterator for &'bv mut BlockVec { +pub struct BlockVecConsumingIter { block_vec_iter : ; BLOCK_SIZE]>> as IntoIterator>::IntoIter, current_block : Option; BLOCK_SIZE]>>, current_idx : usize, @@ -190,3 +235,13 @@ impl Drop for BlockVecConsumingIter while let Some(_) = self.next() {} // Automatically drops all remaining elements of the iterator } } + +impl<'bv, T, const BLOCK_SIZE : usize> FromIterator for BlockVec { + fn from_iter>(iter: Iter) -> Self { + let new_coll = BlockVec::new(); + for v in iter { + new_coll.alloc(v); + } + new_coll + } +} diff --git a/src/errors.rs b/src/errors.rs index 8172d8b..0ffc3dd 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -5,7 +5,6 @@ use std::{ops::Range, path::{Path, PathBuf}, cell::RefCell}; use crate::{ast::Span, linker::{FileUUID, FileUUIDMarker}, arena_alloc::ArenaVector}; use ariadne::*; - use crate::tokenizer::{TokenTypeIdx, get_token_type_name}; #[derive(Debug,Clone,PartialEq,Eq)] @@ -105,6 +104,7 @@ pub fn join_expected_list(expected : &[TokenTypeIdx]) -> String { // Class that collects and manages errors and warnings // Implemented such that it can be shared immutably. This makes many operations to do with parsing easier +// It doesn't allow indexing, so no immutable references to contents can exist #[derive(Debug,Clone)] pub struct ErrorCollector { errors : RefCell>, diff --git a/src/flattening.rs b/src/flattening.rs index 7399c30..8d62435 100644 --- a/src/flattening.rs +++ b/src/flattening.rs @@ -1,9 +1,9 @@ use std::{ops::{Deref, Range}, iter::zip}; use crate::{ - ast::{Span, Value, Module, Expression, SpanExpression, LocalOrGlobal, Operator, AssignableExpression, SpanAssignableExpression, Statement, CodeBlock, IdentifierType, GlobalReference, TypeExpression}, - linker::{Linker, Named, Linkable, get_builtin_uuid, FileUUID}, - errors::{ErrorCollector, error_info}, arena_alloc::{ListAllocator, UUID, UUIDMarker}, tokenizer::kw, typing::{Type, typecheck_unary_operator, get_binary_operator_types, typecheck, typecheck_is_array_indexer} + ast::{Span, Value, Module, Expression, SpanExpression, LocalOrGlobal, Operator, AssignableExpression, SpanAssignableExpression, Statement, CodeBlock, IdentifierType, GlobalReference, TypeExpression, DeclIDMarker}, + linker::{Linker, Named, Linkable, get_builtin_uuid, FileUUID, NamedUUID}, + errors::{ErrorCollector, error_info}, arena_alloc::{ListAllocator, UUID, UUIDMarker}, tokenizer::kw, typing::{Type, typecheck_unary_operator, get_binary_operator_types, typecheck, typecheck_is_array_indexer}, block_vector::BlockVec }; #[derive(Debug,Clone,Copy,PartialEq,Eq,Hash)] @@ -15,21 +15,30 @@ pub type SpanFlatID = (FlatID, Span); pub type FieldID = usize; +#[derive(Debug)] +pub enum ConnectionWritePathElement { + ArrayIdx(SpanFlatID), + //StructField(FieldID) +} + // These are assignable connections #[derive(Debug)] -pub enum ConnectionWrite { - Local(FlatID), - ArrayIdx(Box<(SpanConnectionWrite, SpanFlatID)>), - StructField(Box<(SpanConnectionWrite, FieldID)>) +pub struct ConnectionWrite { + pub root : FlatID, + pub path : Vec, + pub span : Span } -pub type SpanConnectionWrite = (ConnectionWrite, Span); +impl ConnectionWrite { + pub fn simple(root : FlatID, span : Span) -> ConnectionWrite { + ConnectionWrite { root, path: Vec::new(), span } + } +} #[derive(Debug)] pub enum Instantiation { - SubModule{typ : Type, typ_span : Span}, + SubModule{module_uuid : NamedUUID, typ_span : Span, interface_wires : Vec}, PlainWire{typ : Type, typ_span : Span}, - ExtractWire{typ : Type, extract_from : FlatID, field : FieldID}, UnaryOp{typ : Type, op : Operator, right : SpanFlatID}, BinaryOp{typ : Type, op : Operator, left : SpanFlatID, right : SpanFlatID}, ArrayAccess{typ : Type, arr : SpanFlatID, arr_idx : SpanFlatID}, @@ -40,9 +49,8 @@ pub enum Instantiation { impl Instantiation { pub fn get_type(&self) -> &Type { match self { - Instantiation::SubModule{typ, typ_span : _} => typ, + Instantiation::SubModule{module_uuid : _, typ_span : _, interface_wires : _} => panic!("This is not a struct!"), Instantiation::PlainWire{typ, typ_span : _} => typ, - Instantiation::ExtractWire{typ, extract_from : _, field : _} => typ, Instantiation::UnaryOp{typ, op : _, right : _} => typ, Instantiation::BinaryOp{typ, op : _, left : _, right : _} => typ, Instantiation::ArrayAccess{typ, arr : _, arr_idx : _} => typ, @@ -56,13 +64,14 @@ impl Instantiation { pub struct Connection { pub num_regs : u32, pub from : SpanFlatID, - pub to : SpanConnectionWrite, + pub to : ConnectionWrite, pub condition : FlatID } struct FlatteningContext<'l, 'm> { instantiations : ListAllocator, - connections : Vec, + connections : BlockVec, + decl_to_flat_map : ListAllocator, errors : ErrorCollector, linker : &'l Linker, @@ -74,10 +83,7 @@ impl<'l, 'm> FlatteningContext<'l, 'm> { let found = self.instantiations[wire.0].get_type(); typecheck(found, wire.1, expected, context, self.linker, &self.errors) } - fn typecheck_is_array_indexer<'a>(&self, arr_type : &'a Type, span : Span) -> Option<&'a Type> { - typecheck_is_array_indexer(arr_type, span, self.linker, &self.errors) - } - pub fn map_to_type(&mut self, type_expr : &TypeExpression, global_references : &[GlobalReference]) -> Option { + pub fn map_to_type(&self, type_expr : &TypeExpression, global_references : &[GlobalReference]) -> Option { match type_expr { TypeExpression::Named(n) => Some(Type::Named(global_references[*n].1)), TypeExpression::Array(b) => { @@ -90,67 +96,55 @@ impl<'l, 'm> FlatteningContext<'l, 'm> { } // May also error, for example when array accesses happen on non-array types fn get_connectionwrite_type(&self, cw : &ConnectionWrite) -> Option<&Type> { - match cw { - ConnectionWrite::Local(id) => Some(self.instantiations[*id].get_type()), - ConnectionWrite::ArrayIdx(arr_box) => { - let (arr, arr_idx) = arr_box.deref(); - - let index_was_int = self.typecheck(*arr_idx, &Type::Named(get_builtin_uuid("int")), "array index"); - - let arr_type = self.get_connectionwrite_type(&arr.0)?; - let arr_content_type = self.typecheck_is_array_indexer(&arr_type, arr.1)?; - - index_was_int?; // Do both for better typechecking diagnostics - Some(arr_content_type) - }, - ConnectionWrite::StructField(struct_field_box) => { - let ((struct_or_instance, struct_or_instance_span), outside_field) = struct_field_box.deref(); - - let ConnectionWrite::Local(id) = struct_or_instance else {todo!()}; - - let Instantiation::SubModule{typ : Type::Named(instantiation), typ_span} = &self.instantiations[*id] else {todo!()}; - - let Named::Module(found) = &self.linker.links[*instantiation] else {panic!("Instantiation must be module!")}; - - let port_decl = &found.interface.interface_wires[*outside_field]; - - if !port_decl.is_input { - let field_decl_info = error_info(port_decl.span, found.link_info.file, "Output Defined Here"); - self.errors.error_with_info(*struct_or_instance_span, "Cannot write to output of submodule!", vec![field_decl_info]); - return None; + let mut current_type = self.instantiations[cw.root].get_type(); + for p in &cw.path { + match p { + ConnectionWritePathElement::ArrayIdx(idx) => { + let index_was_int = self.typecheck(*idx, &Type::Named(get_builtin_uuid("int")), "array index"); + current_type = typecheck_is_array_indexer(current_type, idx.1, self.linker, &self.errors)?; + index_was_int?; } - - Some(&port_decl.typ) - }, + } } + Some(current_type) } - fn create_connection(&mut self, connection : Connection) -> Option<()> { - let expected_type = self.get_connectionwrite_type(&connection.to.0)?; + fn create_connection(&self, connection : Connection) -> Option<()> { + let expected_type = self.get_connectionwrite_type(&connection.to)?; self.typecheck(connection.from, &expected_type, "connection")?; - self.connections.push(connection); + self.connections.alloc(connection); Some(()) } - fn desugar_func_call(&mut self, func_and_args : &[SpanExpression], closing_bracket_pos : usize, condition : FlatID) -> Option<(&'l Module, FlatID, Range)> { + fn alloc_module_interface(&self, module : &Module, module_uuid : NamedUUID, typ_span : Span) -> Instantiation { + let interface_wires = module.interface.interface_wires.iter().map(|port| { + self.instantiations.alloc(Instantiation::PlainWire { typ: port.typ.clone(), typ_span }) + }).collect(); + + Instantiation::SubModule{module_uuid, typ_span, interface_wires} + } + fn desugar_func_call(&self, func_and_args : &[SpanExpression], closing_bracket_pos : usize, condition : FlatID) -> Option<(&Module, &[FlatID])> { let (name_expr, name_expr_span) = &func_and_args[0]; // Function name is always there - let func_instantiation = match name_expr { + let func_instantiation_id = match name_expr { Expression::Named(LocalOrGlobal::Local(l)) => { - *l + self.decl_to_flat_map[*l] } Expression::Named(LocalOrGlobal::Global(g)) => { - let module_uuid = self.module.link_info.global_references[*g]; - self.instantiations.alloc(Instantiation::SubModule{typ : Type::Named(module_uuid.1), typ_span : *name_expr_span}) + let module_ref = self.module.link_info.global_references[*g]; + + let dependency = self.linker.get_module(module_ref, &self.errors)?; + let new_module_interface = self.alloc_module_interface(dependency, module_ref.1, *name_expr_span); + self.instantiations.alloc(new_module_interface) } _other => { - self.errors.error_basic(*name_expr_span, "Function call cannot be an expression"); + self.errors.error_basic(*name_expr_span, "Function call name cannot be an expression"); return None; } }; - let Instantiation::SubModule{typ : module_type, typ_span} = &self.instantiations[func_instantiation] else {panic!("Instantiation is not named!");}; - let Type::Named(module_id) = module_type else {todo!();}; - let Named::Module(md) = &self.linker.links.globals[*module_id] else {panic!("UUID Is not module!");}; + let func_instantiation = &self.instantiations[func_instantiation_id]; + let Instantiation::SubModule{module_uuid, typ_span, interface_wires} = func_instantiation else {unreachable!("It should be proven {func_instantiation:?} was a Module!");}; + let Named::Module(md) = &self.linker.links.globals[*module_uuid] else {unreachable!("UUID Should be a module!");}; let (inputs, output_range) = md.interface.get_function_sugar_inputs_outputs(); let mut args = &func_and_args[1..]; @@ -176,18 +170,17 @@ impl<'l, 'm> FlatteningContext<'l, 'm> { if self.typecheck(arg_read_side, &md.interface.interface_wires[field].typ, "submodule output") == None { continue; } - let func_instance_connectionwrite = (ConnectionWrite::Local(func_instantiation), *name_expr_span); - let to = (ConnectionWrite::StructField(Box::new((func_instance_connectionwrite, field))), *name_expr_span); - self.create_connection(Connection{num_regs: 0, to, from : arg_read_side, condition}); + let func_input_wire = interface_wires[field]; + self.create_connection(Connection { num_regs: 0, from: arg_read_side, to: ConnectionWrite::simple(func_input_wire, *name_expr_span), condition }); } } - Some((md, func_instantiation, output_range)) + Some((md, &interface_wires[output_range])) } - fn flatten_single_expr(&mut self, (expr, expr_span) : &SpanExpression, condition : FlatID) -> Option { + fn flatten_single_expr(&self, (expr, expr_span) : &SpanExpression, condition : FlatID) -> Option { let single_connection_side = match expr { Expression::Named(LocalOrGlobal::Local(l)) => { - *l + self.decl_to_flat_map[*l] } Expression::Named(LocalOrGlobal::Global(g)) => { let r = self.module.link_info.global_references[*g]; @@ -214,18 +207,18 @@ impl<'l, 'm> FlatteningContext<'l, 'm> { self.instantiations.alloc(Instantiation::BinaryOp{typ : output_type, op : *op, left, right}) } Expression::Array(arr_box) => { - let (left, right) = arr_box.deref(); + let (left, right, bracket_span) = arr_box.deref(); let arr = self.flatten_single_expr(left, condition)?; let arr_idx = self.flatten_single_expr(right, condition)?; let index_was_int = self.typecheck(arr_idx, &Type::Named(get_builtin_uuid("int")), "array index"); let array_type = self.instantiations[arr.0].get_type(); - let typ = self.typecheck_is_array_indexer(array_type, arr.1)?.clone(); + let typ = typecheck_is_array_indexer(array_type, arr.1, self.linker, &self.errors)?.clone(); index_was_int?; // Do both for better typechecking diagnostics self.instantiations.alloc(Instantiation::ArrayAccess{typ, arr, arr_idx}) } Expression::FuncCall(func_and_args) => { - let (md, func_instance, outputs) = self.desugar_func_call(func_and_args, expr_span.1, condition)?; + let (md, outputs) = self.desugar_func_call(func_and_args, expr_span.1, condition)?; if outputs.len() != 1 { let info = error_info(md.link_info.span, md.link_info.file, "Module Defined here"); @@ -233,27 +226,31 @@ impl<'l, 'm> FlatteningContext<'l, 'm> { return None; } - self.instantiations.alloc(Instantiation::ExtractWire{typ: md.interface.interface_wires[outputs.start].typ.clone(), extract_from: func_instance, field: outputs.start}) + outputs[0] } }; Some((single_connection_side, *expr_span)) } - fn flatten_assignable_expr(&mut self, (expr, span) : &SpanAssignableExpression, condition : FlatID) -> Option { - Some((match expr { + fn flatten_assignable_expr(&self, (expr, span) : &SpanAssignableExpression, condition : FlatID) -> Option { + Some(match expr { AssignableExpression::Named{local_idx} => { - ConnectionWrite::Local(*local_idx) + ConnectionWrite{root: self.decl_to_flat_map[*local_idx], path : Vec::new(), span : *span} } AssignableExpression::ArrayIndex(arr_box) => { - let (arr, idx) = arr_box.deref(); + let (arr, idx, bracket_span) = arr_box.deref(); + let flattened_arr_expr_opt = self.flatten_assignable_expr(arr, condition); + let idx_local = self.flatten_single_expr(idx, condition)?; - let flattened_arr_expr = self.flatten_assignable_expr(arr, condition)?; + let mut flattened_arr_expr = flattened_arr_expr_opt?; // only unpack the subexpr after flattening the idx, so we catch all errors + + flattened_arr_expr.path.push(ConnectionWritePathElement::ArrayIdx(idx_local)); - ConnectionWrite::ArrayIdx(Box::new((flattened_arr_expr, idx_local))) + flattened_arr_expr } - }, *span)) + }) } - fn extend_condition(&mut self, condition : FlatID, additional_condition : SpanFlatID) -> FlatID { + fn extend_condition(&self, condition : FlatID, additional_condition : SpanFlatID) -> FlatID { if condition == FlatID::INVALID { additional_condition.0 } else { @@ -262,7 +259,7 @@ impl<'l, 'm> FlatteningContext<'l, 'm> { self.instantiations.alloc(Instantiation::BinaryOp{typ : bool_typ, op: Operator{op_typ : kw("&")}, left : (condition, additional_condition.1), right : additional_condition}) } } - fn flatten_code(&mut self, code : &CodeBlock, condition : FlatID) { + fn flatten_code(&self, code : &CodeBlock, condition : FlatID) { for (stmt, stmt_span) in &code.statements { match stmt { Statement::Declaration(local_id) => { @@ -281,7 +278,7 @@ impl<'l, 'm> FlatteningContext<'l, 'm> { } } Statement::Assign{to, expr : (Expression::FuncCall(func_and_args), func_span), eq_sign_position} => { - let Some((md, instantiation_idx, outputs)) = self.desugar_func_call(&func_and_args, func_span.1, condition) else {return;}; + let Some((md, outputs)) = self.desugar_func_call(&func_and_args, func_span.1, condition) else {return;}; let func_name_span = func_and_args[0].1; let num_func_outputs = outputs.len(); @@ -299,8 +296,7 @@ impl<'l, 'm> FlatteningContext<'l, 'm> { for (field, to_i) in zip(outputs, to) { let Some(write_side) = self.flatten_assignable_expr(&to_i.expr, condition) else {return;}; - let w = self.instantiations.alloc(Instantiation::ExtractWire{typ: md.interface.interface_wires[field].typ.clone(), extract_from: instantiation_idx, field}); - self.create_connection(Connection{num_regs : to_i.num_regs, from: (w, func_name_span), to: write_side, condition}); + self.create_connection(Connection{num_regs : to_i.num_regs, from: (*field, func_name_span), to: write_side, condition}); } }, Statement::Assign{to, expr : non_func_expr, eq_sign_position : _} => { @@ -329,33 +325,44 @@ Must be further processed by flatten, but this requires all modules to have been pub fn make_initial_flattened(module : &Module, linker : &Linker) -> (FlattenedModule, FlattenedInterface) { let mut interface = FlattenedInterface{interface_wires : Vec::new()}; let mut context = FlatteningContext { - instantiations : module.declarations.map(|_,_| Instantiation::Error), - connections : Vec::new(), + instantiations : ListAllocator::new(), + connections : BlockVec::new(), + decl_to_flat_map : module.declarations.iter().map(|_| UUID::INVALID).collect(), errors : ErrorCollector::new(module.link_info.file), module, linker, }; - for (wire_id, decl) in &module.declarations { + for (decl_id, decl) in &module.declarations { let Some(typ) = context.map_to_type(&decl.typ.0, &module.link_info.global_references) else {continue;}; let typ_copy = typ.clone(); let typ_span = decl.typ.1; let decl_typ_root_reference = typ.get_root(); - let inst = match &linker.links.globals[decl_typ_root_reference] { - Named::Constant(c) => { - context.errors.error_basic(typ_span, format!("This should be the type of a declaration, but it refers to the constant '{}'", c.get_full_name())); - Instantiation::Error - } - Named::Module(_) => { - Instantiation::SubModule{typ, typ_span} - } - Named::Type(_) => { - Instantiation::PlainWire{typ, typ_span} + let inst = if decl_typ_root_reference == UUID::INVALID { + Instantiation::Error // Error's covered by linker + } else { + match &linker.links.globals[decl_typ_root_reference] { + Named::Constant(c) => { + context.errors.error_basic(typ_span, format!("This should be the type of a declaration, but it refers to the constant '{}'", c.get_full_name())); + Instantiation::Error + } + Named::Module(md) => { + if let Type::Named(name) = typ { + context.alloc_module_interface(md, name, typ_span) + } else { + todo!("Implement submodule arrays"); + //Instantiation::Error + } + } + Named::Type(_) => { + Instantiation::PlainWire{typ, typ_span} + } } }; - context.instantiations[wire_id] = inst; - + + let wire_id = context.instantiations.alloc(inst); + context.decl_to_flat_map[decl_id] = wire_id; match decl.identifier_type { IdentifierType::Input | IdentifierType::Output => { @@ -371,7 +378,7 @@ pub fn make_initial_flattened(module : &Module, linker : &Linker) -> (FlattenedM } }; - (FlattenedModule{instantiations: context.instantiations, connections: context.connections, errors : context.errors}, interface) + (FlattenedModule{instantiations: context.instantiations, connections: context.connections, decl_to_flat_map : context.decl_to_flat_map, errors : context.errors}, interface) } /* @@ -384,13 +391,14 @@ pub fn flatten(flattened : FlattenedModule, module : &Module, linker : &Linker) let mut context = FlatteningContext { instantiations : flattened.instantiations, connections : flattened.connections, + decl_to_flat_map : flattened.decl_to_flat_map, errors : flattened.errors, module, linker, }; context.flatten_code(&module.code, FlatID::INVALID); - FlattenedModule{instantiations: context.instantiations, connections: context.connections, errors : context.errors} + FlattenedModule{instantiations: context.instantiations, connections: context.connections, decl_to_flat_map : context.decl_to_flat_map, errors : context.errors} } #[derive(Debug)] @@ -435,7 +443,8 @@ impl FlattenedInterface { #[derive(Debug)] pub struct FlattenedModule { pub instantiations : ListAllocator, - pub connections : Vec, + pub connections : BlockVec, + pub decl_to_flat_map : ListAllocator, pub errors : ErrorCollector } @@ -443,7 +452,8 @@ impl FlattenedModule { pub fn empty(file : FileUUID) -> FlattenedModule { FlattenedModule { instantiations : ListAllocator::new(), - connections : Vec::new(), + connections : BlockVec::new(), + decl_to_flat_map : ListAllocator::new(), errors : ErrorCollector::new(file) } } diff --git a/src/instantiation.rs b/src/instantiation.rs new file mode 100644 index 0000000..fbf7847 --- /dev/null +++ b/src/instantiation.rs @@ -0,0 +1,227 @@ +use std::{rc::Rc, ops::Deref, cell::RefCell}; + +use crate::{arena_alloc::{UUID, ListAllocator, UUIDMarker}, ast::{Value, Operator}, typing::{ConcreteType, Type}, flattening::{FlatID, FieldID, Instantiation, FlattenedModule, FlatIDMarker, ConnectionWrite, ConnectionWritePathElement}, errors::{ErrorCollector, error_info}, linker::{Linker, get_builtin_uuid}}; + + + +#[derive(Debug,Clone,Copy,PartialEq,Eq,Hash)] +pub struct WireIDMarker; +impl UUIDMarker for WireIDMarker {const DISPLAY_NAME : &'static str = "wire_";} +pub type WireID = UUID; + +#[derive(Debug,Clone,Copy,PartialEq,Eq,Hash)] +pub struct SubModuleIDMarker; +impl UUIDMarker for SubModuleIDMarker {const DISPLAY_NAME : &'static str = "submodule_";} +pub type SubModuleID = UUID; + +#[derive(Debug)] +pub struct ConnectFrom { + num_regs : u32, + from : WireID, + condition : WireID +} + +#[derive(Debug)] +pub enum ConnectToPathElem { + ArrayConnection{idx_wire : WireID} +} + +#[derive(Debug)] +pub struct Connect { + pub path : Vec, + pub from : ConnectFrom +} + +#[derive(Debug)] +pub enum RealWireDataSource { + Multiplexer{sources : Vec}, + ExtractWire{extract_from : SubModuleID, field : FieldID}, + UnaryOp{op : Operator, right : WireID}, + BinaryOp{op : Operator, left : WireID, right : WireID}, + ArrayAccess{arr : WireID, arr_idx : WireID}, + Constant{value : Value} +} + +#[derive(Debug)] +pub struct RealWire { + source : RealWireDataSource, + original_wire : FlatID, + typ : ConcreteType +} + +#[derive(Debug)] +pub struct SubModuleInstance { + instance : Rc, + interface_wires : Vec +} + +#[derive(Debug)] +pub struct InstantiatedModule { + pub interface : Vec, + pub wires : ListAllocator, + pub submodules : ListAllocator, + pub errors : ErrorCollector +} + +enum SubModuleOrWire { + SubModule(SubModuleID), + Wire(WireID), + Unnasigned +} + +impl SubModuleOrWire { + fn extract_wire(&self) -> WireID { + let Self::Wire(result) = self else {panic!("Failed wire extraction!")}; + *result + } + fn extract_submodule(&self) -> SubModuleID { + let Self::SubModule(result) = self else {panic!("Failed SubModule extraction!")}; + *result + } +} + +struct InstantiationContext<'fl, 'l> { + instance_map : ListAllocator, + wires : ListAllocator, + submodules : ListAllocator, + interface : Vec, + errors : ErrorCollector, + + flattened : &'fl FlattenedModule, + linker : &'l Linker, +} + +impl<'fl, 'l> InstantiationContext<'fl, 'l> { + fn compute_constant(&self, wire : FlatID) -> Value { + let Instantiation::Constant { typ, value } = &self.flattened.instantiations[wire] else {todo!()}; + value.clone() + } + fn concretize_type(&self, typ : &Type) -> ConcreteType { + match typ { + Type::Named(n) => { + ConcreteType::Named(*n) + }, + Type::Array(arr_box) => { + let (arr_content_typ, arr_size_wire) = arr_box.deref(); + let inner_typ = self.concretize_type(arr_content_typ); + let Value::Integer(v) = self.compute_constant(*arr_size_wire) else {panic!("Not an int, should have been solved beforehand!")}; + let arr_usize = u64::try_from(v).expect("Array size should be small enough"); + ConcreteType::Array(Box::new((inner_typ, arr_usize))) + }, + } + } + fn process_connection(&mut self, to : &ConnectionWrite, from : ConnectFrom) { + let mut new_path : Vec = Vec::new(); + + let mut write_to_typ = &self.wires[self.instance_map[to.root].extract_wire()].typ; + + for pe in &to.path { + match pe { + ConnectionWritePathElement::ArrayIdx(arr_idx) => { + let idx_wire = self.instance_map[arr_idx.0].extract_wire(); + + assert!(self.wires[idx_wire].typ == ConcreteType::Named(get_builtin_uuid("int"))); + + new_path.push(ConnectToPathElem::ArrayConnection { idx_wire }); + + let ConcreteType::Array(new_write_to_typ) = write_to_typ else {unreachable!("Cannot not be an array")}; + write_to_typ = &new_write_to_typ.deref().0; + } + } + } + + let found_typ = &self.wires[from.from].typ; + if write_to_typ != found_typ { + todo!(); + } + + let RealWire{typ : _, original_wire: _, source : RealWireDataSource::Multiplexer { sources }} = &mut self.wires[self.instance_map[to.root].extract_wire()] else {unreachable!("Should only be a writeable wire here")}; + + sources.push(Connect{from, path : new_path}) + } + fn instantiate_flattened_module(&mut self) { + for (original_wire, inst) in &self.flattened.instantiations { + let instance_to_add : SubModuleOrWire = match inst { + Instantiation::SubModule{module_uuid: name, typ_span, interface_wires} => { + let interface_real_wires = interface_wires.iter().map(|w| self.instance_map[*w].extract_wire()).collect(); + SubModuleOrWire::SubModule(self.submodules.alloc(SubModuleInstance{instance : self.linker.instantiate(*name), interface_wires : interface_real_wires})) + }, + Instantiation::PlainWire{typ, typ_span} => { + SubModuleOrWire::Wire(self.wires.alloc(RealWire{ typ : self.concretize_type(typ), original_wire, source : RealWireDataSource::Multiplexer {sources : Vec::new()}})) + }, + Instantiation::UnaryOp{typ, op, right} => { + SubModuleOrWire::Wire(self.wires.alloc(RealWire { typ : self.concretize_type(typ), original_wire, source : RealWireDataSource::UnaryOp{op: *op, right: self.instance_map[right.0].extract_wire() }})) + }, + Instantiation::BinaryOp{typ, op, left, right} => { + SubModuleOrWire::Wire(self.wires.alloc(RealWire { typ : self.concretize_type(typ), original_wire, source : RealWireDataSource::BinaryOp{op: *op, left: self.instance_map[left.0].extract_wire(), right: self.instance_map[right.0].extract_wire() }})) + }, + Instantiation::ArrayAccess{typ, arr, arr_idx} => { + SubModuleOrWire::Wire(self.wires.alloc(RealWire { typ : self.concretize_type(typ), original_wire, source : RealWireDataSource::ArrayAccess{arr: self.instance_map[arr.0].extract_wire(), arr_idx: self.instance_map[arr_idx.0].extract_wire() }})) + }, + Instantiation::Constant{typ, value} => { + SubModuleOrWire::Wire(self.wires.alloc(RealWire { typ : self.concretize_type(typ), original_wire, source : RealWireDataSource::Constant{value : value.clone() }})) + }, + Instantiation::Error => {unreachable!()}, + }; + self.instance_map[original_wire] = instance_to_add; + } + for conn in &self.flattened.connections { + let condition = if conn.condition != UUID::INVALID { + self.instance_map[conn.condition].extract_wire() + } else { + UUID::INVALID + }; + let conn_from = ConnectFrom { + num_regs: conn.num_regs, + from: self.instance_map[conn.from.0].extract_wire(), // TODO Span? + condition, + }; + + self.process_connection(&conn.to, conn_from); + } + } +} + + + +#[derive(Debug)] +pub struct InstantiationList { + cache : RefCell>> +} + +impl InstantiationList { + pub fn new() -> Self { + Self{cache : RefCell::new(Vec::new())} + } + + pub fn instantiate(&self, flattened : &FlattenedModule, linker : &Linker) -> Rc { + let mut cache_borrow = self.cache.borrow_mut(); + + // Temporary, no template arguments yet + if cache_borrow.is_empty() { + let mut context = InstantiationContext{ + instance_map : flattened.instantiations.iter().map(|(_, _)| SubModuleOrWire::Unnasigned).collect(), + wires : ListAllocator::new(), + submodules : ListAllocator::new(), + interface : Vec::new(), + flattened : flattened, + linker : linker, + errors : ErrorCollector::new(flattened.errors.file) + }; + + context.instantiate_flattened_module(); + + cache_borrow.push(Rc::new(InstantiatedModule{wires : context.wires, submodules : context.submodules, interface : context.interface, errors : context.errors})); + } + + let instance_id = 0; // Temporary, will always be 0 while not template arguments + cache_borrow[instance_id].clone() + } + + pub fn collect_errors(&self, errors : &ErrorCollector) { + let cache_borrow = self.cache.borrow(); + for inst in cache_borrow.deref() { + errors.ingest(&inst.errors); + } + } +} diff --git a/src/linker.rs b/src/linker.rs index f41e69c..a25b496 100644 --- a/src/linker.rs +++ b/src/linker.rs @@ -1,6 +1,6 @@ -use std::{collections::{HashMap, HashSet}, ops::{IndexMut, Index}}; +use std::{collections::{HashMap, HashSet}, ops::{IndexMut, Index}, rc::Rc}; -use crate::{ast::{Module, LinkInfo, Span, Value, GlobalReference}, arena_alloc::{ArenaAllocator, UUID, UUIDMarker}, parser::{FullParseResult, TokenTreeNode}, tokenizer::Token, errors::{ErrorCollector, error_info}, flattening::{flatten, make_initial_flattened, FlattenedInterface, FlattenedModule}, util::{const_str_position, const_str_position_in_tuples}}; +use crate::{ast::{Module, LinkInfo, Span, Value, GlobalReference}, arena_alloc::{ArenaAllocator, UUID, UUIDMarker}, parser::{FullParseResult, TokenTreeNode}, tokenizer::Token, errors::{ErrorCollector, error_info}, flattening::{flatten, make_initial_flattened, FlattenedInterface, FlattenedModule}, util::{const_str_position, const_str_position_in_tuples}, instantiation::InstantiatedModule}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct NamedUUIDMarker; @@ -334,6 +334,7 @@ impl Linker { for v in &self.files[file_uuid].associated_values { if let Named::Module(md) = &self.links.globals[*v] { errors.ingest(&md.flattened.errors); + md.instantiations.collect_errors(errors); } } } @@ -447,6 +448,9 @@ impl Linker { } pub fn get_constant(&self, GlobalReference(identifier_span, uuid) : GlobalReference, errors : &ErrorCollector) -> Option { + if uuid == UUID::INVALID { + return None; // Error reporting already handled by linking + } match &self.links.globals[uuid] { Named::Constant(NamedConstant::Builtin(_name, v)) => { Some(v.clone()) @@ -467,6 +471,9 @@ impl Linker { } pub fn get_module(&self, GlobalReference(identifier_span, uuid) : GlobalReference, errors : &ErrorCollector) -> Option<&Module> { + if uuid == UUID::INVALID { + return None; // Error reporting already handled by linking + } match &self.links.globals[uuid] { Named::Module(md) => { Some(md) @@ -494,10 +501,8 @@ impl Linker { for (id, named_object) in &self.links.globals { println!("Initializing Flattening for {}", named_object.get_name()); if let Named::Module(md) = named_object { - if !md.link_info.is_fully_linked { - continue; - } - + // Do initial flattening for ALL modules, regardless of linking errors, to get proper interface + // if !md.link_info.is_fully_linked {continue;} let (flt, interface) = make_initial_flattened(md, &self); flattened_vec.push((id, flt)); interface_vec.push((id, interface)); @@ -509,11 +514,16 @@ impl Linker { md.interface = interface; } + let mut to_instantiate_vec : Vec = Vec::new(); + // Then do proper flattening on every module for (id, flattened) in flattened_vec { // println!("Flattening {}", named_object.get_name()); let Named::Module(md) = &self.links.globals[id] else {unreachable!()}; + // Do check for linking errors when generating code, as this could cause the compiler to error + if !md.link_info.is_fully_linked {continue;} let new_flattened = flatten(flattened, md, &self); + let Named::Module(md) = &mut self.links.globals[id] else {unreachable!()}; println!("[[{}]]:", md.link_info.name); println!("\tInstantiations:"); @@ -525,6 +535,18 @@ impl Linker { println!("\t\t{:?}", conn); } md.flattened = new_flattened; + to_instantiate_vec.push(id); } + + for id in to_instantiate_vec { + self.instantiate(id); + } + } + + pub fn instantiate(&self, module_id : NamedUUID) -> Rc { + let Named::Module(md) = &self.links.globals[module_id] else {panic!("{module_id:?} is not a Module!")}; + println!("Instantiating {}", md.link_info.name); + + md.instantiations.instantiate(&md.flattened, self) } } diff --git a/src/main.rs b/src/main.rs index c20fc08..db0a80b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ mod parser; mod errors; mod ast; mod flattening; +mod instantiation; #[cfg(feature = "codegen")] mod codegen; diff --git a/src/parser.rs b/src/parser.rs index 00b419c..6b64689 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,7 +1,7 @@ use num::bigint::BigUint; -use crate::{tokenizer::*, errors::*, ast::*, linker::{FileUUID, NamedUUID}, flattening::{FlatID, FlatIDMarker, FlattenedModule, FlattenedInterface}, arena_alloc::ListAllocator}; +use crate::{tokenizer::*, errors::*, ast::*, linker::{FileUUID, NamedUUID}, flattening::{FlattenedModule, FlattenedInterface}, arena_alloc::ListAllocator, instantiation::InstantiationList}; use std::{iter::Peekable, str::FromStr, ops::Range}; use core::slice::Iter; @@ -105,12 +105,12 @@ pub fn to_token_hierarchy(tokens : &[Token], errors : &mut ErrorCollector) -> Ve } struct LocalVariableContext<'prev, 'file> { - locals : Vec<(&'file str, FlatID)>, + locals : Vec<(&'file str, DeclID)>, prev : Option<&'prev LocalVariableContext<'prev, 'file>> } impl<'prev, 'file> LocalVariableContext<'prev, 'file> { - pub fn get_declaration_for(&self, name : &'file str) -> Option { + pub fn get_declaration_for(&self, name : &'file str) -> Option { for (decl_name, unique_id) in &self.locals { if *decl_name == name { return Some(*unique_id); @@ -122,7 +122,7 @@ impl<'prev, 'file> LocalVariableContext<'prev, 'file> { None } } - pub fn add_declaration(&mut self, new_local_name : &'file str, new_local_unique_id : FlatID) -> Result<(), FlatID> { // Returns conflicting signal declaration + pub fn add_declaration(&mut self, new_local_name : &'file str, new_local_unique_id : DeclID) -> Result<(), DeclID> { // Returns conflicting signal declaration for (existing_local_name, existing_local_id) in &self.locals { if new_local_name == *existing_local_name { return Err(*existing_local_id) @@ -314,7 +314,7 @@ impl<'g, 'file> ASTParserContext<'g, 'file> { } } - fn add_declaration(&mut self, type_expr : SpanTypeExpression, name : TokenContent, identifier_type : IdentifierType, declarations : &mut ListAllocator, scope : &mut LocalVariableContext<'_, 'file>) -> FlatID { + fn add_declaration(&mut self, type_expr : SpanTypeExpression, name : TokenContent, identifier_type : IdentifierType, declarations : &mut ListAllocator, scope : &mut LocalVariableContext<'_, 'file>) -> DeclID { let span = Span(type_expr.1.0, name.position); let decl = SignalDeclaration{typ : type_expr, span, name : self.file_text[name.text.clone()].into(), identifier_type}; let decl_id = declarations.alloc(decl); @@ -391,7 +391,7 @@ impl<'g, 'file> ASTParserContext<'g, 'file> { } else if *typ == kw("[") { let mut arg_token_stream = TokenStream::new(content, bracket_span.0, bracket_span.1); let arg = self.parse_expression(&mut arg_token_stream, scope)?; - base_expr = (Expression::Array(Box::new((base_expr, arg))), total_span) + base_expr = (Expression::Array(Box::new((base_expr, arg, *bracket_span))), total_span) } else { break; } @@ -430,7 +430,7 @@ impl<'g, 'file> ASTParserContext<'g, 'file> { } } - fn parse_signal_declaration(&mut self, token_stream : &mut TokenStream, identifier_type : IdentifierType, declarations : &mut ListAllocator, scope : &mut LocalVariableContext<'_, 'file>) -> Option<()> { + fn parse_signal_declaration(&mut self, token_stream : &mut TokenStream, identifier_type : IdentifierType, declarations : &mut ListAllocator, scope : &mut LocalVariableContext<'_, 'file>) -> Option<()> { let sig_type = self.try_parse_type(token_stream, scope)?; let name = self.eat_identifier(token_stream, "signal declaration")?; self.add_declaration(sig_type, name, identifier_type, declarations, scope); @@ -450,7 +450,7 @@ impl<'g, 'file> ASTParserContext<'g, 'file> { Some(cur_type) } - fn try_parse_declaration(&mut self, token_stream : &mut TokenStream, declarations : &mut ListAllocator, scope : &mut LocalVariableContext<'_, 'file>) -> Option<(FlatID, Span)> { + fn try_parse_declaration(&mut self, token_stream : &mut TokenStream, declarations : &mut ListAllocator, scope : &mut LocalVariableContext<'_, 'file>) -> Option<(DeclID, Span)> { let identifier_type = if token_stream.eat_is_plain(kw("state")).is_some() { IdentifierType::State } else { @@ -463,7 +463,7 @@ impl<'g, 'file> ASTParserContext<'g, 'file> { Some((local_idx, Span::from(name_token.position))) } - fn parse_bundle(&mut self, token_stream : &mut TokenStream, identifier_type : IdentifierType, declarations : &mut ListAllocator, scope : &mut LocalVariableContext<'_, 'file>) { + fn parse_bundle(&mut self, token_stream : &mut TokenStream, identifier_type : IdentifierType, declarations : &mut ListAllocator, scope : &mut LocalVariableContext<'_, 'file>) { while token_stream.peek_is_plain(TOKEN_IDENTIFIER) { if let Some(_) = self.parse_signal_declaration(token_stream, identifier_type, declarations, scope) { @@ -478,7 +478,7 @@ impl<'g, 'file> ASTParserContext<'g, 'file> { } } - fn parse_interface(&mut self, token_stream : &mut TokenStream, declarations : &mut ListAllocator, scope : &mut LocalVariableContext<'_, 'file>) { + fn parse_interface(&mut self, token_stream : &mut TokenStream, declarations : &mut ListAllocator, scope : &mut LocalVariableContext<'_, 'file>) { self.parse_bundle(token_stream, IdentifierType::Input, declarations, scope); if token_stream.eat_is_plain(kw("->")).is_some() { @@ -486,7 +486,7 @@ impl<'g, 'file> ASTParserContext<'g, 'file> { } } - fn parse_statement(&mut self, token_stream : &mut TokenStream, declarations : &mut ListAllocator, scope : &mut LocalVariableContext<'_, 'file>, code_block : &mut CodeBlock) -> Option<()> { + fn parse_statement(&mut self, token_stream : &mut TokenStream, declarations : &mut ListAllocator, scope : &mut LocalVariableContext<'_, 'file>, code_block : &mut CodeBlock) -> Option<()> { let start_at = if let Some(peek) = token_stream.peek() { peek.get_span().0 } else { @@ -561,9 +561,9 @@ impl<'g, 'file> ASTParserContext<'g, 'file> { } }, Expression::Array(b) => { - let (arr, idx) = *b; + let (arr, idx, bracket_span) = *b; let assignable_arr = self.convert_expression_to_assignable_expression(arr)?; - Some((AssignableExpression::ArrayIndex(Box::new((assignable_arr, idx))), span)) + Some((AssignableExpression::ArrayIndex(Box::new((assignable_arr, idx, bracket_span))), span)) }, Expression::Constant(_) => {self.errors.error_basic(span, "Cannot assign to constant"); None}, Expression::UnaryOp(_) => {self.errors.error_basic(span, "Cannot assign to the result of an operator"); None}, @@ -613,7 +613,7 @@ impl<'g, 'file> ASTParserContext<'g, 'file> { return None; } } - fn parse_if_statement(&mut self, token_stream : &mut TokenStream, if_token : &TokenContent, declarations : &mut ListAllocator, scope : &LocalVariableContext<'_, 'file>) -> Option<(Statement, Span)> { + fn parse_if_statement(&mut self, token_stream : &mut TokenStream, if_token : &TokenContent, declarations : &mut ListAllocator, scope : &LocalVariableContext<'_, 'file>) -> Option<(Statement, Span)> { let condition = self.parse_expression(token_stream, &scope)?; let (then_block, then_block_span) = self.eat_block(token_stream, kw("{"), "Then block of if statement")?; @@ -637,7 +637,7 @@ impl<'g, 'file> ASTParserContext<'g, 'file> { Some((Statement::If{condition, then: then_content, els: else_content }, Span(if_token.position, span_end))) } - fn parse_code_block(&mut self, block_tokens : &[TokenTreeNode], span : Span, declarations : &mut ListAllocator, outer_scope : &LocalVariableContext<'_, 'file>) -> CodeBlock { + fn parse_code_block(&mut self, block_tokens : &[TokenTreeNode], span : Span, declarations : &mut ListAllocator, outer_scope : &LocalVariableContext<'_, 'file>) -> CodeBlock { let mut token_stream = TokenStream::new(block_tokens, span.0, span.1); let mut code_block = CodeBlock{statements : Vec::new()}; @@ -698,7 +698,7 @@ impl<'g, 'file> ASTParserContext<'g, 'file> { global_references : replace(&mut self.global_references, Vec::new()), is_fully_linked : false }; - Some(Module{declarations, code, link_info, flattened : FlattenedModule::empty(self.errors.file), interface : FlattenedInterface::default()}) + Some(Module{declarations, code, link_info, flattened : FlattenedModule::empty(self.errors.file), interface : FlattenedInterface::default(), instantiations : InstantiationList::new()}) } fn parse_ast(mut self, outer_token_iter : &mut TokenStream) -> ASTRoot {