Skip to content

Commit

Permalink
Preparation for fully moving spans to Instances
Browse files Browse the repository at this point in the history
  • Loading branch information
VonTum committed Jan 3, 2024
1 parent a093db5 commit affacc4
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 64 deletions.
32 changes: 18 additions & 14 deletions src/flattening.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{ops::{Deref, Range}, iter::zip};

use crate::{
ast::{Span, Module, Expression, SpanExpression, LocalOrGlobal, Operator, AssignableExpression, SpanAssignableExpression, Statement, CodeBlock, IdentifierType, GlobalReference, TypeExpression, DeclIDMarker, DeclID},
ast::{Span, 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, FlatAlloc}, tokenizer::kw, typing::{Type, typecheck_unary_operator, get_binary_operator_types, typecheck, typecheck_is_array_indexer}, value::Value
};
Expand Down Expand Up @@ -56,6 +56,7 @@ pub struct InterfacePort {
#[derive(Debug)]
pub enum WireSource {
NamedWire{read_only : bool, identifier_type : IdentifierType, name : Box<str>, name_token : Option<usize>},
WireRead{from_wire : FlatID}, // Used to add a span to the reference of a wire.
UnaryOp{op : Operator, right : SpanFlatID},
BinaryOp{op : Operator, left : SpanFlatID, right : SpanFlatID},
ArrayAccess{arr : SpanFlatID, arr_idx : SpanFlatID},
Expand Down Expand Up @@ -227,24 +228,27 @@ impl<'l, 'm, 'fl> FlatteningContext<'l, 'm, 'fl> {
Some((md, &interface_wires[output_range]))
}
fn flatten_single_expr(&self, (expr, expr_span) : &SpanExpression, condition : Option<FlatID>) -> Option<SpanFlatID> {
let span = *expr_span; // for more compact constructors
let single_connection_side = match expr {
Expression::Named(LocalOrGlobal::Local(l)) => {
self.decl_to_flat_map[*l].unwrap()
let from_wire = self.decl_to_flat_map[*l].unwrap();
let prev_decl = self.instantiations[from_wire].extract_wire();
self.instantiations.alloc(Instantiation::Wire(WireInstance{typ : prev_decl.typ.clone(), is_compiletime : prev_decl.is_compiletime, span, inst : WireSource::WireRead{from_wire}}))
}
Expression::Named(LocalOrGlobal::Global(g)) => {
let r = self.module.link_info.global_references[*g];
let cst = self.linker.try_get_constant(r, &self.errors)?;
self.instantiations.alloc(Instantiation::Wire(WireInstance{typ : cst.get_type_of_constant(), is_compiletime : true, span : *expr_span, inst : WireSource::Constant{value : cst}}))
self.instantiations.alloc(Instantiation::Wire(WireInstance{typ : cst.get_type_of_constant(), is_compiletime : true, span, inst : WireSource::Constant{value : cst}}))
}
Expression::Constant(cst) => {
self.instantiations.alloc(Instantiation::Wire(WireInstance{typ : cst.get_type_of_constant(), is_compiletime : true, span : *expr_span, inst : WireSource::Constant{value : cst.clone()}}))
self.instantiations.alloc(Instantiation::Wire(WireInstance{typ : cst.get_type_of_constant(), is_compiletime : true, span, inst : WireSource::Constant{value : cst.clone()}}))
}
Expression::UnaryOp(op_box) => {
let (op, _op_pos, operate_on) = op_box.deref();
let right = self.flatten_single_expr(operate_on, condition)?;
let found = self.instantiations[right.0].extract_wire();
let output_type = typecheck_unary_operator(*op, &found.typ, right.1, self.linker, &self.errors);
self.instantiations.alloc(Instantiation::Wire(WireInstance{typ : output_type, is_compiletime : found.is_compiletime, span : *expr_span, inst : WireSource::UnaryOp{op : *op, right}}))
self.instantiations.alloc(Instantiation::Wire(WireInstance{typ : output_type, is_compiletime : found.is_compiletime, span, inst : WireSource::UnaryOp{op : *op, right}}))
}
Expression::BinOp(binop_box) => {
let (left_expr, op, _op_pos, right_expr) = binop_box.deref();
Expand All @@ -254,7 +258,7 @@ impl<'l, 'm, 'fl> FlatteningContext<'l, 'm, 'fl> {
self.typecheck(left, &input_left_type, &format!("{op} left"))?;
self.typecheck(right, &input_right_type, &format!("{op} right"))?;
let is_constant = self.instantiations[left.0].extract_wire().is_compiletime && self.instantiations[right.0].extract_wire().is_compiletime;
self.instantiations.alloc(Instantiation::Wire(WireInstance{typ : output_type, is_compiletime: is_constant, span : *expr_span, inst : WireSource::BinaryOp{op : *op, left, right}}))
self.instantiations.alloc(Instantiation::Wire(WireInstance{typ : output_type, is_compiletime: is_constant, span, inst : WireSource::BinaryOp{op : *op, left, right}}))
}
Expression::Array(arr_box) => {
let (left, right, _bracket_span) = arr_box.deref();
Expand All @@ -267,14 +271,14 @@ impl<'l, 'm, 'fl> FlatteningContext<'l, 'm, 'fl> {
index_was_int?; // Do both for better typechecking diagnostics
let idx_is_constant = self.instantiations[arr_idx.0].extract_wire().is_compiletime;
let is_constant = self.instantiations[arr.0].extract_wire().is_compiletime && idx_is_constant;
self.instantiations.alloc(Instantiation::Wire(WireInstance{typ, is_compiletime: is_constant, span : *expr_span, inst : WireSource::ArrayAccess{arr, arr_idx}}))
self.instantiations.alloc(Instantiation::Wire(WireInstance{typ, is_compiletime: is_constant, span, inst : WireSource::ArrayAccess{arr, arr_idx}}))
}
Expression::FuncCall(func_and_args) => {
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");
self.errors.error_with_info(*expr_span, "A function called in this context may only return one result. Split this function call into a separate line instead.", vec![info]);
self.errors.error_with_info(span, "A function called in this context may only return one result. Split this function call into a separate line instead.", vec![info]);
return None;
}

Expand Down Expand Up @@ -348,7 +352,8 @@ impl<'l, 'm, 'fl> FlatteningContext<'l, 'm, 'fl> {
Named::Type(_) => {
assert!(decl.identifier_type != IdentifierType::Input);
assert!(decl.identifier_type != IdentifierType::Output);
Instantiation::Wire(WireInstance{typ, is_compiletime : decl.identifier_type == IdentifierType::Generative, span : typ_span, inst : WireSource::NamedWire{read_only : false, identifier_type : decl.identifier_type, name : decl.name.clone(), name_token : Some(decl.name_token)}})
let is_compiletime = decl.identifier_type == IdentifierType::Generative;
Instantiation::Wire(WireInstance{typ, is_compiletime, span : typ_span, inst : WireSource::NamedWire{read_only : false, identifier_type : decl.identifier_type, name : decl.name.clone(), name_token : Some(decl.name_token)}})
}
}
} else {
Expand Down Expand Up @@ -568,11 +573,10 @@ impl FlattenedModule {
match &self.instantiations[item] {
Instantiation::Wire(wire) => {
match &wire.inst {
WireSource::NamedWire{read_only : _, identifier_type : _, name : _, name_token : _} => {}
WireSource::UnaryOp{op : _, right} => {func(right.0);}
WireSource::BinaryOp{op : _, left, right} => {func(left.0); func(right.0);}
WireSource::ArrayAccess{arr, arr_idx} => {func(arr.0); func(arr_idx.0)}
WireSource::Constant{value : _} => {}
WireSource::WireRead{from_wire} => {
func(*from_wire);
}
_other => {}
}
}
Instantiation::SubModule{module_uuid : _, name : _, typ_span : _, interface_wires} => {
Expand Down
111 changes: 61 additions & 50 deletions src/instantiation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> {
for p in conn_path {
match p {
ConnectionWritePathElement::ArrayIdx(idx) => {
let Some(idx_val) = self.get_generation_value(idx) else {return None};
let Some(idx_val) = self.get_generation_value(idx.0) else {return None};
let Some(idx_val) = self.extract_integer_from_value::<usize>(idx_val, idx.1) else {return None};
result.push(ConnectionWritePathElementComputed::ArrayIdx(idx_val))
}
Expand Down Expand Up @@ -272,35 +272,38 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> {
};

}
fn get_generation_value(&self, v : &SpanFlatID) -> Option<&Value> {
if let SubModuleOrWire::CompileTimeValue(vv) = &self.generation_state[v.0] {
fn get_generation_value(&self, v : FlatID) -> Option<&Value> {
if let SubModuleOrWire::CompileTimeValue(vv) = &self.generation_state[v] {
Some(vv)
} else {
self.errors.error_basic(v.1, "This variable is not set at this point!");
self.errors.error_basic(self.module.flattened.instantiations[v].extract_wire().span, "This variable is not set at this point!");
None
}
}
fn compute_compile_time(&self, wire_inst : &WireSource, typ : &ConcreteType) -> Option<Value> {
Some(match &wire_inst {
Some(match wire_inst {
WireSource::NamedWire{read_only, identifier_type: _, name : _, name_token : _} => {
/*Do nothing (in fact re-initializes the wire to 'empty'), just corresponds to wire declaration*/
if *read_only {
todo!("Modules can't be computed at compile time yet");
}
typ.get_initial_val(self.linker)
}
WireSource::WireRead{from_wire} => {
self.get_generation_value(*from_wire)?.clone()
}
WireSource::UnaryOp{op, right} => {
let right_val = self.get_generation_value(right)?;
let right_val = self.get_generation_value(right.0)?;
compute_unary_op(*op, right_val)
}
WireSource::BinaryOp{op, left, right} => {
let left_val = self.get_generation_value(left)?;
let right_val = self.get_generation_value(right)?;
let left_val = self.get_generation_value(left.0)?;
let right_val = self.get_generation_value(right.0)?;
compute_binary_op(left_val, *op, right_val)
}
WireSource::ArrayAccess{arr, arr_idx} => {
let Value::Array(arr_val) = self.get_generation_value(arr)? else {return None};
let arr_idx_val = self.get_generation_value(arr_idx)?;
let Value::Array(arr_val) = self.get_generation_value(arr.0)? else {return None};
let arr_idx_val = self.get_generation_value(arr_idx.0)?;
let idx : usize = self.extract_integer_from_value(arr_idx_val, arr_idx.1)?;
if let Some(item) = arr_val.get(idx) {
item.clone()
Expand Down Expand Up @@ -329,6 +332,52 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> {
}
}
}
fn wire_to_real_wire(&mut self, w: &WireInstance, typ : ConcreteType, original_wire : FlatID) -> Option<WireID> {
let (name, source) = match &w.inst {
WireSource::NamedWire{read_only, identifier_type, name, name_token : _} => {
let source = if *read_only {
RealWireDataSource::ReadOnly
} else {
// TODO initial value
let is_state = if *identifier_type == IdentifierType::State{StateInitialValue::State{initial_value: Value::Unset}} else {StateInitialValue::Combinatorial};
RealWireDataSource::Multiplexer{is_state, sources : Vec::new()}
};
(Some(name.clone()), source)
}
WireSource::WireRead{from_wire} => {
let WireSource::NamedWire { read_only, identifier_type, name, name_token } = &self.module.flattened.instantiations[*from_wire].extract_wire().inst else {unreachable!("WireReads must point to a NamedWire!")};
return Some(self.generation_state[*from_wire].extract_wire())
}
WireSource::UnaryOp{op, right} => {
let right = self.get_wire_or_constant_as_wire(right)?;
(None, RealWireDataSource::UnaryOp{op: *op, right})
}
WireSource::BinaryOp{op, left, right} => {
let left = self.get_wire_or_constant_as_wire(left)?;
let right = self.get_wire_or_constant_as_wire(right)?;
(None, RealWireDataSource::BinaryOp{op: *op, left, right})
}
WireSource::ArrayAccess{arr, arr_idx} => {
let arr = self.get_wire_or_constant_as_wire(arr)?;
match &self.generation_state[arr_idx.0] {
SubModuleOrWire::SubModule(_) => unreachable!(),
SubModuleOrWire::Unnasigned => unreachable!(),
SubModuleOrWire::Wire(w) => {
(None, RealWireDataSource::ArrayAccess{arr, arr_idx: *w})
}
SubModuleOrWire::CompileTimeValue(v) => {
let arr_idx = self.extract_integer_from_value(v, arr_idx.1)?;
(None, RealWireDataSource::ConstArrayAccess{arr, arr_idx})
}
}
}
WireSource::Constant{value: _} => {
unreachable!("Constant cannot be non-compile-time");
}
};
let name = name.unwrap_or_else(|| self.get_unique_name());
Some(self.wires.alloc(RealWire{ name, typ, original_wire, source}))
}
fn instantiate_flattened_module(&mut self) {
for (original_wire, inst) in &self.module.flattened.instantiations {
let instance_to_add : SubModuleOrWire = match inst {
Expand All @@ -348,46 +397,8 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> {
assert!(value_computed.is_of_type(&typ));
SubModuleOrWire::CompileTimeValue(value_computed)
} else {
let (name, source) = match &w.inst {
WireSource::NamedWire{read_only, identifier_type, name, name_token : _} => {
let source = if *read_only {
RealWireDataSource::ReadOnly
} else {
// TODO initial value
let is_state = if *identifier_type == IdentifierType::State{StateInitialValue::State{initial_value: Value::Unset}} else {StateInitialValue::Combinatorial};
RealWireDataSource::Multiplexer{is_state, sources : Vec::new()}
};
(Some(name.clone()), source)
}
WireSource::UnaryOp{op, right} => {
let Some(right) = self.get_wire_or_constant_as_wire(right) else {return};
(None, RealWireDataSource::UnaryOp{op: *op, right})
}
WireSource::BinaryOp{op, left, right} => {
let Some(left) = self.get_wire_or_constant_as_wire(left) else {return};
let Some(right) = self.get_wire_or_constant_as_wire(right) else {return};
(None, RealWireDataSource::BinaryOp{op: *op, left, right})
}
WireSource::ArrayAccess{arr, arr_idx} => {
let Some(arr) = self.get_wire_or_constant_as_wire(arr) else {return};
match &self.generation_state[arr_idx.0] {
SubModuleOrWire::SubModule(_) => unreachable!(),
SubModuleOrWire::Unnasigned => unreachable!(),
SubModuleOrWire::Wire(w) => {
(None, RealWireDataSource::ArrayAccess{arr, arr_idx: *w})
}
SubModuleOrWire::CompileTimeValue(v) => {
let Some(arr_idx) = self.extract_integer_from_value(v, arr_idx.1) else {return};
(None, RealWireDataSource::ConstArrayAccess{arr, arr_idx})
}
}
}
WireSource::Constant{value: _} => {
unreachable!("Constant cannot be non-compile-time");
}
};
let name = name.unwrap_or_else(|| self.get_unique_name());
SubModuleOrWire::Wire(self.wires.alloc(RealWire{ name, typ, original_wire, source}))
let Some(wire_found) = self.wire_to_real_wire(w, typ, original_wire) else {return};
SubModuleOrWire::Wire(wire_found)
}
}
Instantiation::Connection(conn) => {
Expand Down

0 comments on commit affacc4

Please sign in to comment.