diff --git a/src/protocol/tests/utils.rs b/src/protocol/tests/utils.rs index 63ff0f95929262c11c44f701f0f31015589658dd..7dff07dacf06403751b5379528373bca3cd94c92 100644 --- a/src/protocol/tests/utils.rs +++ b/src/protocol/tests/utils.rs @@ -218,7 +218,7 @@ impl AstOkTester { pub(crate) fn for_function(self, name: &str, f: F) -> Self { let mut found = false; for definition in self.heap.definitions.iter() { - if let Definition::Function(definition) = definition { + if let Definition::Procedure(definition) = definition { if definition.identifier.value.as_str() != name { continue; } @@ -296,8 +296,8 @@ impl<'a> StructTester<'a> { pub(crate) fn assert_size_alignment(mut self, monomorph: &str, size: usize, alignment: usize) -> Self { self = self.assert_has_monomorph(monomorph); let (mono_idx, _) = has_monomorph(self.ctx, self.ast_def.this.upcast(), monomorph); - let mono_idx = mono_idx.unwrap(); - let mono = self.ctx.types.get_monomorph(mono_idx); + let type_id = mono_idx.unwrap(); + let mono = self.ctx.types.get_monomorph(type_id); assert!( mono.size == size && mono.alignment == alignment, @@ -507,25 +507,23 @@ impl<'a> UnionTester<'a> { pub(crate) struct FunctionTester<'a> { ctx: TestCtx<'a>, - def: &'a FunctionDefinition, + def: &'a ProcedureDefinition, } impl<'a> FunctionTester<'a> { - fn new(ctx: TestCtx<'a>, def: &'a FunctionDefinition) -> Self { + fn new(ctx: TestCtx<'a>, def: &'a ProcedureDefinition) -> Self { Self{ ctx, def } } pub(crate) fn for_variable(self, name: &str, f: F) -> Self { // Seek through the blocks in order to find the variable - let wrapping_block_id = seek_stmt( - self.ctx.heap, self.def.body.upcast(), - &|stmt| { - if let Statement::Block(block) = stmt { - for local_id in &block.locals { - let var = &self.ctx.heap[*local_id]; - if var.identifier.value.as_str() == name { - return true; - } + let wrapping_scope = seek_scope( + self.ctx.heap, self.def.scope, + &|scope| { + for variable_id in scope.variables.iter().copied() { + let var = &self.ctx.heap[variable_id]; + if var.identifier.value.as_str() == name { + return true; } } @@ -534,13 +532,13 @@ impl<'a> FunctionTester<'a> { ); let mut found_local_id = None; - if let Some(block_id) = wrapping_block_id { - // Found the right block, find the variable inside the block again - let block_stmt = self.ctx.heap[block_id].as_block(); - for local_id in &block_stmt.locals { - let var = &self.ctx.heap[*local_id]; - if var.identifier.value.as_str() == name { - found_local_id = Some(*local_id); + if let Some(scope_id) = wrapping_scope { + // Found the right scope, find the variable inside the block again + let scope = &self.ctx.heap[scope_id]; + for variable_id in scope.variables.iter().copied() { + let variable = &self.ctx.heap[variable_id]; + if variable.identifier.value.as_str() == name { + found_local_id = Some(variable_id); } } } @@ -702,11 +700,11 @@ impl<'a> FunctionTester<'a> { use crate::protocol::*; // Assuming the function is not polymorphic - let definition_id = self.def.this.upcast(); + let definition_id = self.def.this; let func_type = [ConcreteTypePart::Function(definition_id, 0)]; - let mono_index = self.ctx.types.get_procedure_monomorph_index(&definition_id, &func_type).unwrap(); + let mono_index = self.ctx.types.get_procedure_monomorph_type_id(&definition_id.upcast(), &func_type).unwrap(); - let mut prompt = Prompt::new(&self.ctx.types, &self.ctx.heap, self.def.this.upcast(), mono_index, ValueGroup::new_stack(Vec::new())); + let mut prompt = Prompt::new(&self.ctx.types, &self.ctx.heap, definition_id, mono_index, ValueGroup::new_stack(Vec::new())); let mut call_context = FakeRunContext{}; loop { let result = prompt.step(&self.ctx.types, &self.ctx.heap, &self.ctx.modules, &mut call_context); @@ -750,8 +748,11 @@ impl<'a> VariableTester<'a> { pub(crate) fn assert_concrete_type(self, expected: &str) -> Self { // Lookup concrete type in type table - let mono_data = get_procedure_monomorph(&self.ctx.heap, &self.ctx.types, self.definition_id); - let concrete_type = &mono_data.expr_data[self.var_expr.unique_id_in_definition as usize].expr_type; + let mono_proc = get_procedure_monomorph(&self.ctx.heap, &self.ctx.types, self.definition_id); + let mono_index = mono_proc.monomorph_index; + let mono_data = &self.ctx.heap[self.definition_id].as_procedure().monomorphs[mono_index as usize]; + let expr_info = &mono_data.expr_info[self.var_expr.type_index as usize]; + let concrete_type = &self.ctx.types.get_monomorph(expr_info.type_id).concrete_type; // Serialize and check let serialized = concrete_type.display_name(self.ctx.heap); @@ -784,9 +785,11 @@ impl<'a> ExpressionTester<'a> { pub(crate) fn assert_concrete_type(self, expected: &str) -> Self { // Lookup concrete type - let mono_data = get_procedure_monomorph(&self.ctx.heap, &self.ctx.types, self.definition_id); - let expr_index = self.expr.get_unique_id_in_definition(); - let concrete_type = &mono_data.expr_data[expr_index as usize].expr_type; + let mono_proc = get_procedure_monomorph(&self.ctx.heap, &self.ctx.types, self.definition_id); + let mono_index = mono_proc.monomorph_index; + let mono_data = &self.ctx.heap[self.definition_id].as_procedure().monomorphs[mono_index as usize]; + let expr_info = &mono_data.expr_info[self.expr.type_index() as usize]; + let concrete_type = &self.ctx.types.get_monomorph(expr_info.type_id).concrete_type; // Serialize and check type let serialized = concrete_type.display_name(self.ctx.heap); @@ -808,18 +811,15 @@ impl<'a> ExpressionTester<'a> { } fn get_procedure_monomorph<'a>(heap: &Heap, types: &'a TypeTable, definition_id: DefinitionId) -> &'a ProcedureMonomorph { - let ast_definition = &heap[definition_id]; - let func_type = if ast_definition.is_function() { - [ConcreteTypePart::Function(definition_id, 0)] - } else if ast_definition.is_component() { - [ConcreteTypePart::Component(definition_id, 0)] + let ast_definition = heap[definition_id].as_procedure(); + let func_type = if ast_definition.kind == ProcedureKind::Function { + [ConcreteTypePart::Function(ast_definition.this, 0)] } else { - assert!(false); - unreachable!() + [ConcreteTypePart::Component(ast_definition.this, 0)] }; - let mono_index = types.get_procedure_monomorph_index(&definition_id, &func_type).unwrap(); - let mono_data = types.get_procedure_monomorph(mono_index); + let mono_index = types.get_procedure_monomorph_type_id(&definition_id, &func_type).unwrap(); + let mono_data = types.get_monomorph(mono_index).variant.as_procedure(); mono_data } @@ -928,12 +928,16 @@ fn has_equal_num_monomorphs(ctx: TestCtx, num: usize, definition_id: DefinitionI // Again: inefficient, but its testing code let mut num_on_type = 0; - for mono in &ctx.types.mono_lookup.monomorphs { + for mono in &ctx.types.mono_types { match &mono.concrete_type.parts[0] { - ConcreteTypePart::Instance(def_id, _) | + ConcreteTypePart::Instance(def_id, _) => { + if *def_id == definition_id { + num_on_type += 1; + } + } ConcreteTypePart::Function(def_id, _) | ConcreteTypePart::Component(def_id, _) => { - if *def_id == definition_id { + if def_id.upcast() == definition_id { num_on_type += 1; } }, @@ -944,13 +948,13 @@ fn has_equal_num_monomorphs(ctx: TestCtx, num: usize, definition_id: DefinitionI (num_on_type == num, num_on_type) } -fn has_monomorph(ctx: TestCtx, definition_id: DefinitionId, serialized_monomorph: &str) -> (Option, String) { +fn has_monomorph(ctx: TestCtx, definition_id: DefinitionId, serialized_monomorph: &str) -> (Option, String) { // Note: full_buffer is just for error reporting let mut full_buffer = String::new(); let mut has_match = None; full_buffer.push('['); - let mut append_to_full_buffer = |concrete_type: &ConcreteType, mono_idx: usize| { + let mut append_to_full_buffer = |concrete_type: &ConcreteType, type_id: TypeId| { if full_buffer.len() != 1 { full_buffer.push_str(", "); } @@ -959,22 +963,22 @@ fn has_monomorph(ctx: TestCtx, definition_id: DefinitionId, serialized_monomorph let first_idx = full_buffer.len(); full_buffer.push_str(concrete_type.display_name(ctx.heap).as_str()); if &full_buffer[first_idx..] == serialized_monomorph { - has_match = Some(mono_idx as i32); + has_match = Some(type_id); } full_buffer.push('"'); }; // Bit wasteful, but this is (temporary?) testing code: - for (mono_idx, mono) in ctx.types.mono_lookup.monomorphs.iter().enumerate() { + for (_mono_idx, mono) in ctx.types.mono_types.iter().enumerate() { let got_definition_id = match &mono.concrete_type.parts[0] { - ConcreteTypePart::Instance(v, _) | + ConcreteTypePart::Instance(v, _) => *v, ConcreteTypePart::Function(v, _) | - ConcreteTypePart::Component(v, _) => *v, + ConcreteTypePart::Component(v, _) => v.upcast(), _ => DefinitionId::new_invalid(), }; if got_definition_id == definition_id { - append_to_full_buffer(&mono.concrete_type, mono_idx); + append_to_full_buffer(&mono.concrete_type, mono.type_id); } } @@ -1098,23 +1102,36 @@ fn seek_stmt bool>(heap: &Heap, start: StatementId, f: &F) }, Statement::Labeled(stmt) => seek_stmt(heap, stmt.body, f), Statement::If(stmt) => { - if let Some(id) = seek_stmt(heap, stmt.true_body.upcast(), f) { + if let Some(id) = seek_stmt(heap, stmt.true_case.body, f) { return Some(id); - } else if let Some(false_body) = stmt.false_body { - if let Some(id) = seek_stmt(heap, false_body.upcast(), f) { + } else if let Some(false_body) = stmt.false_case { + if let Some(id) = seek_stmt(heap, false_body.body, f) { return Some(id); } } None }, - Statement::While(stmt) => seek_stmt(heap, stmt.body.upcast(), f), - Statement::Synchronous(stmt) => seek_stmt(heap, stmt.body.upcast(), f), + Statement::While(stmt) => seek_stmt(heap, stmt.body, f), + Statement::Synchronous(stmt) => seek_stmt(heap, stmt.body, f), _ => None }; matched } +fn seek_scope bool>(heap: &Heap, start: ScopeId, f: &F) -> Option { + let scope = &heap[start]; + if f(scope) { return Some(start); } + + for child_scope_id in scope.nested.iter().copied() { + if let Some(result) = seek_scope(heap, child_scope_id, f) { + return Some(result); + } + } + + return None; +} + fn seek_expr_in_expr bool>(heap: &Heap, start: ExpressionId, f: &F) -> Option { let expr = &heap[start]; if f(expr) { return Some(start); } @@ -1215,9 +1232,9 @@ fn seek_expr_in_stmt bool>(heap: &Heap, start: StatementId Statement::If(stmt) => { None .or_else(|| seek_expr_in_expr(heap, stmt.test, f)) - .or_else(|| seek_expr_in_stmt(heap, stmt.true_body.upcast(), f)) - .or_else(|| if let Some(false_body) = stmt.false_body { - seek_expr_in_stmt(heap, false_body.upcast(), f) + .or_else(|| seek_expr_in_stmt(heap, stmt.true_case.body, f)) + .or_else(|| if let Some(false_body) = stmt.false_case { + seek_expr_in_stmt(heap, false_body.body, f) } else { None }) @@ -1225,10 +1242,10 @@ fn seek_expr_in_stmt bool>(heap: &Heap, start: StatementId Statement::While(stmt) => { None .or_else(|| seek_expr_in_expr(heap, stmt.test, f)) - .or_else(|| seek_expr_in_stmt(heap, stmt.body.upcast(), f)) + .or_else(|| seek_expr_in_stmt(heap, stmt.body, f)) }, Statement::Synchronous(stmt) => { - seek_expr_in_stmt(heap, stmt.body.upcast(), f) + seek_expr_in_stmt(heap, stmt.body, f) }, Statement::Return(stmt) => { for expr_id in &stmt.expressions { @@ -1250,23 +1267,10 @@ fn seek_expr_in_stmt bool>(heap: &Heap, start: StatementId struct FakeRunContext{} impl RunContext for FakeRunContext { - fn performed_put(&mut self, _port: PortId) -> bool { - unreachable!("'put' called in compiler testing code") - } - - fn performed_get(&mut self, _port: PortId) -> Option { - unreachable!("'get' called in compiler testing code") - } - - fn fires(&mut self, _port: PortId) -> Option { - unreachable!("'fires' called in compiler testing code") - } - - fn performed_fork(&mut self) -> Option { - unreachable!("'fork' called in compiler testing code") - } - - fn created_channel(&mut self) -> Option<(Value, Value)> { - unreachable!("channel created in compiler testing code") - } + fn performed_put(&mut self, _port: PortId) -> bool { unreachable!() } + fn performed_get(&mut self, _port: PortId) -> Option { unreachable!() } + fn fires(&mut self, _port: PortId) -> Option { unreachable!() } + fn performed_fork(&mut self) -> Option { unreachable!() } + fn created_channel(&mut self) -> Option<(Value, Value)> { unreachable!() } + fn performed_select_wait(&mut self) -> Option { unreachable!() } } \ No newline at end of file