diff --git a/src/protocol/ast.rs b/src/protocol/ast.rs index 63762b6dadd95850af6bb4b2325310725ccb67ea..3510e80f484af804fb41047d1ff0c38d14abd87c 100644 --- a/src/protocol/ast.rs +++ b/src/protocol/ast.rs @@ -495,6 +495,8 @@ pub enum ConcreteTypePart { Slice, Input, Output, + // Tuple: variable number of nested types, will never be 1 + Tuple(u32), // User defined type with any number of nested types Instance(DefinitionId, u32), // instance of data type Function(DefinitionId, u32), // instance of function @@ -513,6 +515,7 @@ impl ConcreteTypePart { 0, Array | Slice | Input | Output => 1, + Tuple(num_embedded) => *num_embedded, Instance(_, num_embedded) => *num_embedded, Function(_, num_embedded) => *num_embedded, Component(_, num_embedded) => *num_embedded, @@ -535,25 +538,28 @@ impl ConcreteType { /// Returns an iterator over the subtrees that are type arguments (e.g. an /// array element's type, or a polymorphic type's arguments) to the /// provided parent type (specified by its index in the `parts` array). - pub(crate) fn embedded_iter<'a>(&'a self, parent_part_idx: usize) -> ConcreteTypeIter<'a> { - let num_embedded = self.parts[parent_part_idx].num_embedded(); - return ConcreteTypeIter{ - concrete: self, - idx_embedded: 0, - num_embedded, - part_idx: parent_part_idx + 1, - } + pub(crate) fn embedded_iter(&self, parent_part_idx: usize) -> ConcreteTypeIter { + return ConcreteTypeIter::new(&self.parts, parent_part_idx); } + /// Construct a human-readable name for the type. Because this performs + /// a string allocation don't use it for anything else then displaying the + /// type to the user. + pub(crate) fn display_name(&self, heap: &Heap) -> String { + return Self::type_parts_display_name(self.parts.as_slice(), heap); + } + + // --- Utilities that operate on slice of parts + /// Given the starting position of a type tree, determine the exclusive /// ending index. - pub(crate) fn subtree_end_idx(&self, start_idx: usize) -> usize { + pub(crate) fn type_parts_subtree_end_idx(parts: &[ConcreteTypePart], start_idx: usize) -> usize { let mut depth = 1; - let num_parts = self.parts.len(); + let num_parts = parts.len(); debug_assert!(start_idx < num_parts); - for part_idx in start_idx..self.parts.len() { - let depth_change = self.parts[part_idx].num_embedded() as i32 - 1; + for part_idx in start_idx..parts.len() { + let depth_change = parts[part_idx].num_embedded() as i32 - 1; depth += depth_change; debug_assert!(depth >= 0); @@ -566,85 +572,108 @@ impl ConcreteType { return 0; } - /// Construct a human-readable name for the type. Because this performs - /// a string allocation don't use it for anything else then displaying the - /// type to the user. - pub(crate) fn display_name(&self, heap: &Heap) -> String { - fn display_part(parts: &[ConcreteTypePart], heap: &Heap, mut idx: usize, target: &mut String) -> usize { - use ConcreteTypePart as CTP; - use crate::protocol::parser::token_parsing::*; - - let cur_idx = idx; - idx += 1; // increment by 1, because it always happens - - match parts[cur_idx] { - CTP::Void => { target.push_str("void"); }, - CTP::Message => { target.push_str(KW_TYPE_MESSAGE_STR); }, - CTP::Bool => { target.push_str(KW_TYPE_BOOL_STR); }, - CTP::UInt8 => { target.push_str(KW_TYPE_UINT8_STR); }, - CTP::UInt16 => { target.push_str(KW_TYPE_UINT16_STR); }, - CTP::UInt32 => { target.push_str(KW_TYPE_UINT32_STR); }, - CTP::UInt64 => { target.push_str(KW_TYPE_UINT64_STR); }, - CTP::SInt8 => { target.push_str(KW_TYPE_SINT8_STR); }, - CTP::SInt16 => { target.push_str(KW_TYPE_SINT16_STR); }, - CTP::SInt32 => { target.push_str(KW_TYPE_SINT32_STR); }, - CTP::SInt64 => { target.push_str(KW_TYPE_SINT64_STR); }, - CTP::Character => { target.push_str(KW_TYPE_CHAR_STR); }, - CTP::String => { target.push_str(KW_TYPE_STRING_STR); }, - CTP::Array | CTP::Slice => { - idx = display_part(parts, heap, idx, target); - target.push_str("[]"); - }, - CTP::Input => { - target.push_str(KW_TYPE_IN_PORT_STR); - target.push('<'); - idx = display_part(parts, heap, idx, target); - target.push('>'); - }, - CTP::Output => { - target.push_str(KW_TYPE_OUT_PORT_STR); + /// Produces a human-readable representation of the concrete type parts + fn type_parts_display_name(parts: &[ConcreteTypePart], heap: &Heap) -> String { + let mut name = String::with_capacity(128); + let _final_idx = Self::render_type_part_at(parts, heap, 0, &mut name); + debug_assert_eq!(_final_idx, parts.len()); + + return name; + } + + /// Produces a human-readable representation of a single type part. Lower + /// level utility for `type_parts_display_name`. + fn render_type_part_at(parts: &[ConcreteTypePart], heap: &Heap, mut idx: usize, target: &mut String) -> usize { + use ConcreteTypePart as CTP; + use crate::protocol::parser::token_parsing::*; + + let cur_idx = idx; + idx += 1; // increment by 1, because it always happens + + match parts[cur_idx] { + CTP::Void => { target.push_str("void"); }, + CTP::Message => { target.push_str(KW_TYPE_MESSAGE_STR); }, + CTP::Bool => { target.push_str(KW_TYPE_BOOL_STR); }, + CTP::UInt8 => { target.push_str(KW_TYPE_UINT8_STR); }, + CTP::UInt16 => { target.push_str(KW_TYPE_UINT16_STR); }, + CTP::UInt32 => { target.push_str(KW_TYPE_UINT32_STR); }, + CTP::UInt64 => { target.push_str(KW_TYPE_UINT64_STR); }, + CTP::SInt8 => { target.push_str(KW_TYPE_SINT8_STR); }, + CTP::SInt16 => { target.push_str(KW_TYPE_SINT16_STR); }, + CTP::SInt32 => { target.push_str(KW_TYPE_SINT32_STR); }, + CTP::SInt64 => { target.push_str(KW_TYPE_SINT64_STR); }, + CTP::Character => { target.push_str(KW_TYPE_CHAR_STR); }, + CTP::String => { target.push_str(KW_TYPE_STRING_STR); }, + CTP::Array | CTP::Slice => { + idx = Self::render_type_part_at(parts, heap, idx, target); + target.push_str("[]"); + }, + CTP::Input => { + target.push_str(KW_TYPE_IN_PORT_STR); + target.push('<'); + idx = Self::render_type_part_at(parts, heap, idx, target); + target.push('>'); + }, + CTP::Output => { + target.push_str(KW_TYPE_OUT_PORT_STR); + target.push('<'); + idx = Self::render_type_part_at(parts, heap, idx, target); + target.push('>'); + }, + CTP::Tuple(num_parts) => { + target.push('('); + if num_parts != 0 { + idx = Self::render_type_part_at(parts, heap, idx, target); + for _ in 1..num_parts { + target.push(','); + idx = Self::render_type_part_at(parts, heap, idx, target); + } + } + target.push(')'); + }, + CTP::Instance(definition_id, num_poly_args) | + CTP::Function(definition_id, num_poly_args) | + CTP::Component(definition_id, num_poly_args) => { + let definition = &heap[definition_id]; + target.push_str(definition.identifier().value.as_str()); + + if num_poly_args != 0 { target.push('<'); - idx = display_part(parts, heap, idx, target); - target.push('>'); - }, - CTP::Instance(definition_id, num_poly_args) | - CTP::Function(definition_id, num_poly_args) | - CTP::Component(definition_id, num_poly_args) => { - let definition = &heap[definition_id]; - target.push_str(definition.identifier().value.as_str()); - - if num_poly_args != 0 { - target.push('<'); - for poly_arg_idx in 0..num_poly_args { - if poly_arg_idx != 0 { - target.push(','); - idx = display_part(parts, heap, idx, target); - } + for poly_arg_idx in 0..num_poly_args { + if poly_arg_idx != 0 { + target.push(','); + idx = Self::render_type_part_at(parts, heap, idx, target); } - target.push('>'); } + target.push('>'); } } - - idx } - let mut name = String::with_capacity(128); - let _final_idx = display_part(&self.parts, heap, 0, &mut name); - debug_assert_eq!(_final_idx, self.parts.len()); - - return name; + idx } } #[derive(Debug)] pub struct ConcreteTypeIter<'a> { - concrete: &'a ConcreteType, + parts: &'a [ConcreteTypePart], idx_embedded: u32, num_embedded: u32, part_idx: usize, } +impl<'a> ConcreteTypeIter<'a> { + pub(crate) fn new(parts: &'a[ConcreteTypePart], parent_idx: usize) -> Self { + let num_embedded = parts[parent_idx].num_embedded(); + return ConcreteTypeIter{ + parts, + idx_embedded: 0, + num_embedded, + part_idx: parent_idx + 1, + } + } +} + impl<'a> Iterator for ConcreteTypeIter<'a> { type Item = &'a [ConcreteTypePart]; @@ -655,12 +684,12 @@ impl<'a> Iterator for ConcreteTypeIter<'a> { // Retrieve the subtree of interest let start_idx = self.part_idx; - let end_idx = self.concrete.subtree_end_idx(start_idx); + let end_idx = ConcreteType::type_parts_subtree_end_idx(&self.parts, start_idx); self.idx_embedded += 1; self.part_idx = end_idx; - return Some(&self.concrete.parts[start_idx..end_idx]); + return Some(&self.parts[start_idx..end_idx]); } }