diff --git a/src/protocol/ast.rs b/src/protocol/ast.rs index 5c53156902b10df749a1e2f88698a757bd10e025..8eb367d928941e37bd987f820a3feab632a9da34 100644 --- a/src/protocol/ast.rs +++ b/src/protocol/ast.rs @@ -526,6 +526,21 @@ impl Default for ConcreteType { } 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, + } + } + + /// Given the starting position of a type tree, determine the exclusive + /// ending index. pub(crate) fn subtree_end_idx(&self, start_idx: usize) -> usize { let mut depth = 1; let num_parts = self.parts.len(); @@ -544,6 +559,102 @@ impl ConcreteType { debug_assert!(false, "incorrectly constructed ConcreteType instance"); 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 { + let mut name = String::with_capacity(128); + + 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); + target.push('<'); + idx = display_part(parts, heap, idx, target); + target.push('>'); + }, + CTP::Instance(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); + } + } + target.push('>'); + } + } + } + + idx + } + + let _final_idx = display_part(&self.parts, heap, 0, &mut target); + debug_assert_eq!(_final_idx, self.parts.len()); + + return name; + } +} + +#[derive(Debug)] +pub struct ConcreteTypeIter<'a> { + concrete: &'a ConcreteType, + idx_embedded: u32, + num_embedded: u32, + part_idx: usize, +} + +impl<'a> Iterator for ConcreteTypeIter<'a> { + type Item = &'a [ConcreteTypePart]; + + fn next(&'a mut self) -> Option { + if self.idx_embedded == self.num_embedded { + return None; + } + + // Retrieve the subtree of interest + let start_idx = self.part_idx; + let end_idx = self.concrete.subtree_end_idx(start_idx); + + self.idx_embedded += 1; + self.part_idx = end_idx; + + return Some(&self.concrete.parts[start_idx..end_idx]); + } } #[derive(Debug, Clone, Copy)]