Skip to content

Commit

Permalink
First steps towards doing linking while flattening
Browse files Browse the repository at this point in the history
  • Loading branch information
VonTum committed Jan 10, 2024
1 parent 5cc7f65 commit 0505b50
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 79 deletions.
48 changes: 19 additions & 29 deletions src/flattening.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::{ops::{Deref, Range}, iter::zip};
use std::{ops::{Deref, Range}, iter::zip, cell::{RefCell, Ref}};

use crate::{
ast::{Span, Module, Expression, SpanExpression, LocalOrGlobal, Operator, AssignableExpression, SpanAssignableExpression, Statement, CodeBlock, IdentifierType, TypeExpression, DeclIDMarker, DeclID, SpanTypeExpression},
linker::{Linker, Named, Linkable, NamedUUID, FileUUID},
linker::{Linker, Named, Linkable, NamedUUID, FileUUID, GlobalResolver, ResolvedGlobals},
errors::{ErrorCollector, error_info}, arena_alloc::{UUID, UUIDMarker, FlatAlloc, UUIDRange}, typing::{Type, typecheck_unary_operator, get_binary_operator_types, typecheck, typecheck_is_array_indexer, BOOL_TYPE, INT_TYPE}, value::Value
};

Expand Down Expand Up @@ -178,37 +178,23 @@ impl Instantiation {
}
}

struct FlatteningContext<'inst, 'l, 'm> {
struct FlatteningContext<'inst, 'l, 'm, 'resolved> {
decl_to_flat_map : FlatAlloc<Option<FlatID>, DeclIDMarker>,
instantiations : &'inst mut FlatAlloc<Instantiation, FlatIDMarker>,
errors : ErrorCollector,
is_remote_declaration : Option<NamedUUID>,

linker : &'l Linker,
linker : GlobalResolver<'l, 'resolved>,
module : &'m Module,
}

impl<'inst, 'l, 'm> FlatteningContext<'inst, 'l, 'm> {
pub fn map_to_type(&mut self, type_expr : &SpanTypeExpression) -> Type {
impl<'inst, 'l, 'm, 'resolved> FlatteningContext<'inst, 'l, 'm, 'resolved> {
fn map_to_type(&mut self, type_expr : &SpanTypeExpression) -> Type {
match &type_expr.0 {
TypeExpression::Named(n) => {
if let Some(found_ref) = self.module.link_info.global_references[*n].1 {
let named = &self.linker.links.globals[found_ref];
match named {
Named::Module(_) => {
self.errors.error_basic(type_expr.1, format!("This should be a type, but it refers to the module '{}'", named.get_full_name()));
Type::Error
}
Named::Constant(_) => {
self.errors.error_basic(type_expr.1, format!("This should be a type, but it refers to the constant '{}'", named.get_full_name()));
Type::Error
}
Named::Type(_typ) => {
Type::Named(found_ref)
}
}
if let Some(typ_id) = &self.linker.try_get_type(self.module.link_info.global_references[*n], &self.errors) {
Type::Named(*typ_id)
} else {
// Error report handled by linker
Type::Error
}
}
Expand All @@ -233,7 +219,7 @@ impl<'inst, 'l, 'm> FlatteningContext<'inst, 'l, 'm> {
if ONLY_ALLOW_TYPES {
if let TypeExpression::Named(n) = &decl.typ.0 {
if let Some(possible_module_ref) = self.module.link_info.global_references[*n].1 {
if let Named::Module(md) = &self.linker.links.globals[possible_module_ref] {
if let Some(md) = &self.linker.is_module(possible_module_ref) {
return self.alloc_module_interface(decl.name.clone(), md,possible_module_ref, decl.typ.1)
}
}
Expand Down Expand Up @@ -270,7 +256,7 @@ impl<'inst, 'l, 'm> FlatteningContext<'inst, 'l, 'm> {
instantiations: self.instantiations,
errors: ErrorCollector::new(module.link_info.file), // Temporary ErrorCollector, unused
is_remote_declaration: Some(module_uuid),
linker: self.linker,
linker: self.linker.new_sublinker(module.link_info.file),
module,
};

Expand Down Expand Up @@ -304,7 +290,7 @@ impl<'inst, 'l, 'm> FlatteningContext<'inst, 'l, 'm> {
}
};
let func_instantiation = &self.instantiations[func_instantiation_id].extract_submodule();
let Named::Module(md) = &self.linker.links.globals[func_instantiation.module_uuid] else {unreachable!("UUID Should be a module!")};
let md = self.linker.get_module(func_instantiation.module_uuid);

let submodule_local_wires = func_instantiation.local_wires.clone();

Expand Down Expand Up @@ -528,7 +514,8 @@ pub struct FlattenedModule {
pub instantiations : FlatAlloc<Instantiation, FlatIDMarker>,
pub errors : ErrorCollector,
pub outputs_start : usize,
pub interface_ports : Box<[FlatID]>
pub interface_ports : Box<[FlatID]>,
pub resolved_globals : ResolvedGlobals
}

impl FlattenedModule {
Expand All @@ -537,7 +524,8 @@ impl FlattenedModule {
instantiations : FlatAlloc::new(),
errors : ErrorCollector::new(file),
interface_ports : Box::new([]),
outputs_start : 0
outputs_start : 0,
resolved_globals : ResolvedGlobals::new()
}
}

Expand All @@ -560,12 +548,13 @@ impl FlattenedModule {
*/
pub fn initialize(linker : &Linker, module : &Module, starts_with_errors : bool) -> FlattenedModule {
let mut instantiations = FlatAlloc::new();
let resolved_globals : RefCell<ResolvedGlobals> = RefCell::new(ResolvedGlobals::new());
let mut context = FlatteningContext{
decl_to_flat_map: module.declarations.iter().map(|_| None).collect(),
instantiations: &mut instantiations,
errors: ErrorCollector::new(module.link_info.file),
is_remote_declaration : None,
linker,
linker : GlobalResolver::new(linker, module.link_info.file, &resolved_globals),
module,
};
context.errors.did_error.set(starts_with_errors);
Expand All @@ -578,7 +567,8 @@ impl FlattenedModule {
errors : context.errors,
instantiations : instantiations,
interface_ports,
outputs_start : module.outputs_start
outputs_start : module.outputs_start,
resolved_globals : resolved_globals.into_inner()
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/instantiation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,9 +381,9 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> {
let typ = self.concretize_type(&wire_decl.typ, wire_decl.typ_span)?;
if wire_decl.identifier_type == IdentifierType::Generative {
/*Do nothing (in fact re-initializes the wire to 'empty'), just corresponds to wire declaration*/
if wire_decl.read_only {
/*if wire_decl.read_only { // Don't know why this check is *here*
todo!("Modules can't be computed at compile time yet");
}
}*/
let initial_value = typ.get_initial_val(self.linker);
assert!(initial_value.is_of_type(&typ));
SubModuleOrWire::CompileTimeValue(initial_value)
Expand Down
169 changes: 121 additions & 48 deletions src/linker.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{collections::{HashMap, HashSet}, ops::{IndexMut, Index}, rc::Rc};
use std::{collections::{HashMap, HashSet}, ops::{IndexMut, Index}, rc::Rc, cell::RefCell};

use crate::{ast::{Module, LinkInfo, Span, GlobalReference}, arena_alloc::{ArenaAllocator, UUID, UUIDMarker}, parser::{FullParseResult, TokenTreeNode}, tokenizer::Token, errors::{ErrorCollector, error_info}, flattening::FlattenedModule, util::{const_str_position, const_str_position_in_tuples}, instantiation::InstantiatedModule, value::Value};

Expand Down Expand Up @@ -424,14 +424,105 @@ impl Linker {
self.add_reserved_file(file, parse_result);
}

pub fn get_module(&self, uuid : NamedUUID) -> &Module {
let Named::Module(md) = &self.links.globals[uuid] else {unreachable!()};
md
pub fn recompile_all(&mut self) {
// First create initial flattening for everything, to produce the necessary interfaces

let module_ids : Vec<NamedUUID> = self.links.globals.iter().filter_map(|(id,v)| {
if let Named::Module(_) = v {
Some(id)
} else {
None
}
}).collect();
for id in &module_ids {
let Named::Module(md) = &self.links.globals[*id] else {unreachable!()};

println!("Flattening {}", md.link_info.name);

let mut flattened = FlattenedModule::initialize(&self, md, !md.link_info.is_fully_linked);
println!("Typechecking {}", &md.link_info.name);
flattened.typecheck(self);
flattened.find_unused_variables();

let Named::Module(md) = &mut self.links.globals[*id] else {unreachable!()};
md.flattened = flattened;
md.instantiations.clear_instances();
}

// Can't merge these loops, because instantiation can only be done once all modules have been type checked
for (id, named_object) in &self.links.globals {
if let Named::Module(md) = named_object {
println!("[[{}]]:", md.link_info.name);
md.print_flattened_module();
let inst = self.instantiate(id);
}
}
}

pub fn instantiate(&self, module_id : NamedUUID) -> Option<Rc<InstantiatedModule>> {
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.link_info.name, &md.flattened, self)
}
}

#[derive(Debug)]
pub struct ResolvedGlobals {
referenced_globals : Vec<NamedUUID>,
all_resolved : bool
}

impl ResolvedGlobals {
pub fn new() -> ResolvedGlobals {
ResolvedGlobals{referenced_globals : Vec::new(), all_resolved : true}
}
}

pub struct GlobalResolver<'linker, 'resolved_list> {
linker : &'linker Linker,
file : &'linker FileData,

resolved_globals : &'resolved_list RefCell<ResolvedGlobals>
}

impl<'linker, 'resolved_list> GlobalResolver<'linker, 'resolved_list> {
pub fn new(linker : &'linker Linker, file_id : FileUUID, resolved_globals : &'resolved_list RefCell<ResolvedGlobals>) -> GlobalResolver<'linker, 'resolved_list> {
GlobalResolver{linker, file : &linker.files[file_id], resolved_globals}
}

pub fn new_sublinker(&self, file_id : FileUUID) -> GlobalResolver<'linker, 'resolved_list> {
GlobalResolver{linker : self.linker, file : &self.linker.files[file_id], resolved_globals : self.resolved_globals}
}

pub fn resolve_global(&self, name : Span) -> Option<NamedUUID> {
let name = self.file.get_token_text(name.assert_is_single_token());

let mut resolved_globals = self.resolved_globals.borrow_mut();
if let Some(found) = self.linker.links.global_namespace.get(name) {
resolved_globals.referenced_globals.push(*found);
Some(*found)
} else {
resolved_globals.all_resolved = false;
None
}
}

pub fn get_module(&self, uuid : NamedUUID) -> &'linker Module {
self.is_module(uuid).unwrap()
}

pub fn is_module(&self, uuid : NamedUUID) -> Option<&'linker Module> {
if let Named::Module(md) = &self.linker.links.globals[uuid] {
Some(md)
} else {
None
}
}

pub fn try_get_constant(&self, GlobalReference(identifier_span, ref_uuid) : GlobalReference, errors : &ErrorCollector) -> Option<Value> {
if let Some(uuid) = ref_uuid {
match &self.links.globals[uuid] {
match &self.linker.links.globals[uuid] {
Named::Constant(NamedConstant::Builtin(_name, v)) => {
Some(v.clone())
},
Expand All @@ -453,11 +544,11 @@ impl Linker {
}
}

pub fn try_get_module(&self, GlobalReference(identifier_span, ref_uuid) : GlobalReference, errors : &ErrorCollector) -> Option<&Module> {
pub fn try_get_type(&self, GlobalReference(identifier_span, ref_uuid) : GlobalReference, errors : &ErrorCollector) -> Option<NamedUUID> {
if let Some(uuid) = ref_uuid {
match &self.links.globals[uuid] {
Named::Module(md) => {
Some(md)
match &self.linker.links.globals[uuid] {
Named::Type(_t) => {
Some(uuid)
},
other => {
let info = other.get_linking_error_location();
Expand All @@ -468,7 +559,7 @@ impl Linker {
};
let name = info.name;
let ident_type = info.named_type;
errors.error_with_info(identifier_span, format!("{ident_type} {name} is not a Module!"), infos);
errors.error_with_info(identifier_span, format!("{ident_type} {name} is not a Type!"), infos);
None
}
}
Expand All @@ -477,45 +568,27 @@ impl Linker {
}
}

pub fn recompile_all(&mut self) {
// First create initial flattening for everything, to produce the necessary interfaces

let module_ids : Vec<NamedUUID> = self.links.globals.iter().filter_map(|(id,v)| {
if let Named::Module(_) = v {
Some(id)
} else {
None
}
}).collect();
for id in &module_ids {
let Named::Module(md) = &self.links.globals[*id] else {unreachable!()};

println!("Flattening {}", md.link_info.name);

let mut flattened = FlattenedModule::initialize(&self, md, !md.link_info.is_fully_linked);
println!("Typechecking {}", &md.link_info.name);
flattened.typecheck(self);
flattened.find_unused_variables();

let Named::Module(md) = &mut self.links.globals[*id] else {unreachable!()};
md.flattened = flattened;
md.instantiations.clear_instances();
}

// Can't merge these loops, because instantiation can only be done once all modules have been type checked
for (id, named_object) in &self.links.globals {
if let Named::Module(md) = named_object {
println!("[[{}]]:", md.link_info.name);
md.print_flattened_module();
let inst = self.instantiate(id);
pub fn try_get_module(&self, GlobalReference(identifier_span, ref_uuid) : GlobalReference, errors : &ErrorCollector) -> Option<&'linker Module> {
if let Some(uuid) = ref_uuid {
match &self.linker.links.globals[uuid] {
Named::Module(md) => {
Some(md)
},
other => {
let info = other.get_linking_error_location();
let infos = if let Some((file, span)) = info.location {
vec![error_info(span, file, "Defined here")]
} else {
vec![]
};
let name = info.name;
let ident_type = info.named_type;
errors.error_with_info(identifier_span, format!("{ident_type} {name} is not a Module!"), infos);
None
}
}
} else {
None
}
}

pub fn instantiate(&self, module_id : NamedUUID) -> Option<Rc<InstantiatedModule>> {
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.link_info.name, &md.flattened, self)
}
}

0 comments on commit 0505b50

Please sign in to comment.