Changeset - e9af393acc7d
[Not reviewed]
0 3 0
mh - 4 years ago 2021-12-10 15:19:32
contact@maxhenger.nl
Support for tuples in ParserType parser
3 files changed with 532 insertions and 37 deletions:
0 comments (0 inline, 0 general)
src/protocol/input_source.rs
Show inline comments
 
@@ -451,10 +451,18 @@ impl ParseError {
 
    }
 

	
 
    pub fn with_info_at_span(self, source: &InputSource, span: InputSpan, msg: String) -> Self {
 
        self.with_at_span(StatementKind::Info, source, span, msg)
 
    }
 

	
 
    pub fn with_info_str_at_pos(self, source: &InputSource, pos: InputPosition, msg: &str) -> Self {
 
        self.with_at_span(
 
            StatementKind::Info, source,
 
            InputSpan::from_positions(pos, pos.with_offset(1)),
 
            msg.to_string()
 
        )
 
    }
 

	
 
    pub fn with_info_str_at_span(self, source: &InputSource, span: InputSpan, msg: &str) -> Self {
 
        self.with_at_span(StatementKind::Info, source, span, msg.to_string())
 
    }
 
}
src/protocol/parser/pass_definitions.rs
Show inline comments
 
use crate::protocol::ast::*;
 
use super::symbol_table::*;
 
use super::{Module, ModuleCompilationPhase, PassCtx};
 
use super::tokens::*;
 
use super::token_parsing::*;
 
use crate::protocol::input_source::{InputSource as InputSource, InputPosition as InputPosition, InputSpan, ParseError};
 
use super::pass_definitions_types::*;
 

	
 
use crate::protocol::input_source::{InputSource, InputPosition, InputSpan, ParseError};
 
use crate::collections::*;
 

	
 
/// Parses all the tokenized definitions into actual AST nodes.
 
pub(crate) struct PassDefinitions {
 
    // State associated with the definition currently being processed
 
    cur_definition: DefinitionId,
 
    // Itty bitty parsing machines
 
    type_parser: ParserTypeParser,
 
    // Temporary buffers of various kinds
 
    buffer: String,
 
    struct_fields: ScopedBuffer<StructFieldDefinition>,
 
    enum_variants: ScopedBuffer<EnumVariantDefinition>,
 
    union_variants: ScopedBuffer<UnionVariantDefinition>,
 
    variables: ScopedBuffer<VariableId>,
 
@@ -22,12 +26,13 @@ pub(crate) struct PassDefinitions {
 
}
 

	
 
impl PassDefinitions {
 
    pub(crate) fn new() -> Self {
 
        Self{
 
            cur_definition: DefinitionId::new_invalid(),
 
            type_parser: ParserTypeParser::new(),
 
            buffer: String::with_capacity(128),
 
            struct_fields: ScopedBuffer::new_reserved(128),
 
            enum_variants: ScopedBuffer::new_reserved(128),
 
            union_variants: ScopedBuffer::new_reserved(128),
 
            variables: ScopedBuffer::new_reserved(128),
 
            expressions: ScopedBuffer::new_reserved(128),
src/protocol/parser/pass_definitions_types.rs
Show inline comments
 
use crate::protocol::*;
 
use crate::protocol::parser::*;
 
use crate::protocol::parser::token_parsing::*;
 

	
 
struct Entry {
 
    element: ParserTypeElement,
 
    depth: i32,
 
}
 

	
 
#[derive(Copy, Clone)]
 
#[derive(Copy, Clone, PartialEq, Eq)]
 
enum DepthKind {
 
    Tuple, // because we had a `(` token
 
    PolyArgs, // because we had a `<` token
 
}
 

	
 
struct DepthElement {
 
    kind: DepthKind,
 
    entry_index: u32, // in `entries` array of parser
 
    pos: InputPosition,
 
}
 

	
 
/// Temporarily keep the error around in unevaluated format because sometimes
 
/// when we evaluate a `ParserType`, we perform some backtracking if it fails.
 
enum ParserTypeError {
 
    ExpectedAType(InputPosition),
 
    MessageAt(InputPosition, &'static str),
 
    TwoMessageAt(InputPosition, &'static str, InputPosition, &'static str),
 
/// Current parsing state, for documentation's sake: types may be named, or may
 
/// be tuples. Named types may have polymorphic arguments (if the type
 
/// declaration allows) and a type may be turned into an array of that type by
 
/// postfixing a "[]".
 
enum ParseState {
 
    TypeMaybePolyArgs,  // just parsed a type, might have poly arguments
 
    TypeNeverPolyArgs,  // just parsed a type that cannot have poly arguments
 
    PolyArgStart,       // just opened a polymorphic argument list
 
    TupleStart,         // just opened a tuple list
 
    ParsedComma,        // just had a comma
 
}
 

	
 
/// Parsers tokens into `ParserType` instances (yes, the name of the struct is
 
/// silly). Essentially a little state machine with its own temporary storage.
 
pub(crate) struct ParserTypeParser {
 
    entries: Vec<Entry>,
 
    depths: Vec<DepthElement>,
 
    parse_state: ParseState,
 
    first_pos: InputPosition,
 
    last_pos: InputPosition,
 
}
 

	
 
impl ParserTypeParser {
 
    pub(crate) fn new() -> Self {
 
        return Self{
 
            entries: Vec::with_capacity(16),
 
            depths: Vec::with_capacity(16),
 
            parse_state: ParseState::TypeMaybePolyArgs,
 
            first_pos: InputPosition{ line: 0, offset: 0 },
 
            last_pos: InputPosition{ line: 0, offset: 0 }
 
        }
 
    }
 

	
 
    pub(crate) fn consume_parser_type(
 
        &mut self,
 
        source: &InputSource, iter: &mut TokenIter,
 
        symbols: &SymbolTable, heap: &Heap, poly_vars: &[Identifier],
 
        cur_scope: SymbolScope, wrapping_definition: DefinitionId,
 
        &mut self, iter: &mut TokenIter, heap: &Heap, source: &InputSource,
 
        symbols: &SymbolTable, poly_vars: &[Identifier],
 
        wrapping_definition: DefinitionId, cur_scope: SymbolScope,
 
        allow_inference: bool, inside_angular_bracket: Option<InputPosition>,
 
    ) -> Result<ParserType, ParserTypeError> {
 
        // Make sure we start in an empty state
 
        debug_assert!(self.entries.is_empty());
 
        debug_assert!(self.depths.is_empty());
 
    ) -> Result<ParserType, ParseError> {
 
        // Prepare
 
        self.entries.clear();
 
        self.depths.clear();
 

	
 
        // Setup processing
 
        if let Some(bracket_pos) = inside_angular_bracket {
 
            self.push_depth(DepthKind::PolyArgs, bracket_pos);
 
            self.push_depth(DepthKind::PolyArgs, u32::MAX, bracket_pos);
 
        }
 

	
 
        let first_element = match iter.next() {
 
        let initial_state = match iter.next() {
 
            Some(TokenKind::Ident) => {
 
                let element = Self::consume_parser_type_element(
 
                    iter, source, heap, symbols, wrapping_definition, poly_vars, cur_scope, allow_inference
 
                )?;
 
                self.first_pos = element.element_span.begin;
 
                self.last_pos = element.element_span.end;
 

	
 
                self.entries.push(Entry{
 
                    element,
 
                    depth: self.cur_depth(),
 
                });
 

	
 
                ParseState::TypeMaybePolyArgs
 
            },
 
            Some(TokenKind::OpenParen) => {
 
                let tuple_start_pos = iter.next_start_position();
 
                self.push_depth(DepthKind::Tuple, tuple_start_pos);
 
                self.first_pos = tuple_start_pos; // last pos will be set later, this is a tuple
 

	
 
                let tuple_entry_index = self.entries.len() as u32;
 
                self.push_depth(DepthKind::Tuple, tuple_entry_index, tuple_start_pos);
 
                self.entries.push(Entry{
 
                    element: ParserTypeElement{
 
                        element_span: InputSpan::from_positions(tuple_start_pos, tuple_start_pos),
 
                        variant: ParserTypeVariant::Tuple(0),
 
                    },
 
                    depth: self.cur_depth(),
 
                });
 
                iter.consume();
 

	
 
                ParseState::PolyArgStart
 
            },
 
            _ => return Err(ParserTypeError::MessageAt(iter.last_valid_pos(), "expected a type")),
 
            _ => return Err(ParseError::new_error_str_at_pos(source, iter.last_valid_pos(), "expected a type")),
 
        };
 

	
 
        self.parse_state = initial_state;
 

	
 
        // Depth stack and entries are initialized, continue until depth stack
 
        // is empty, or until an unexpected set of tokens is encountered
 
        while !self.depths.is_empty() {
 
            let next = iter.next();
 

	
 
            match self.parse_state {
 
                ParseState::TypeMaybePolyArgs => {
 
                    // Allowed tokens: , < > >> ) [
 
                    match next {
 
                        Some(TokenKind::Comma) => self.consume_comma(iter),
 
                        Some(TokenKind::OpenAngle) => self.consume_open_angle(iter),
 
                        Some(TokenKind::CloseAngle) => self.consume_close_angle(source, iter)?,
 
                        Some(TokenKind::ShiftRight) => self.consume_double_close_angle(source, iter)?,
 
                        Some(TokenKind::CloseParen) => self.consume_close_paren(source, iter)?,
 
                        Some(TokenKind::OpenSquare) => self.consume_square_parens(source, iter)?,
 
                        _ => return Err(ParseError::new_error_str_at_pos(
 
                            source, iter.last_valid_pos(),
 
                            "unexpected token: expected ',', '<', '>', '<<', ')' or '['"
 
                        )),
 
                    }
 
                },
 
                ParseState::TypeNeverPolyArgs => {
 
                    // Allowed tokens: , > >> ) [
 
                    match next {
 
                        Some(TokenKind::Comma) => self.consume_comma(iter),
 
                        Some(TokenKind::CloseAngle) => self.consume_close_angle(source, iter)?,
 
                        Some(TokenKind::ShiftRight) => self.consume_double_close_angle(source, iter)?,
 
                        Some(TokenKind::CloseParen) => self.consume_close_paren(source, iter)?,
 
                        Some(TokenKind::OpenSquare) => self.consume_square_parens(source, iter)?,
 
                        _ => return Err(ParseError::new_error_str_at_pos(
 
                            source, iter.last_valid_pos(),
 
                            "unexpected token: expected ',', '>', '>>', ')' or '['"
 
                        )),
 
                    }
 
                },
 
                ParseState::PolyArgStart => {
 
                    // Allowed tokens: ident (
 
                    match next {
 
                        Some(TokenKind::Ident) => self.consume_type_idents(
 
                            source, heap, symbols, wrapping_definition, poly_vars, cur_scope, allow_inference, iter
 
                        )?,
 
                        Some(TokenKind::OpenParen) => self.consume_open_paren(iter),
 
                        _ => return Err(ParseError::new_error_str_at_pos(
 
                            source, iter.last_valid_pos(),
 
                            "unexpected token: expected typename or '('"
 
                        )),
 
                    }
 
                },
 
                ParseState::TupleStart => {
 
                    // Allowed tokens: ident )
 
                    match next {
 
                        Some(TokenKind::Ident) => self.consume_type_idents(
 
                            source, heap, symbols, wrapping_definition, poly_vars, cur_scope, allow_inference, iter
 
                        )?,
 
                        Some(TokenKind::CloseParen) => self.consume_close_paren(source, iter)?,
 
                        _ => return Err(ParseError::new_error_str_at_pos(
 
                            source, iter.last_valid_pos(),
 
                            "unexpected token: expected typename or ')'"
 
                        )),
 
                    }
 
                },
 
                ParseState::ParsedComma => {
 
                    // Allowed tokens: ident ( > >> )
 
                    match next {
 
                        Some(TokenKind::Ident) => self.consume_type_idents(
 
                            source, heap, symbols, wrapping_definition, poly_vars, cur_scope, allow_inference, iter
 
                        )?,
 
                        Some(TokenKind::OpenParen) => self.consume_open_paren(iter),
 
                        Some(TokenKind::CloseAngle) => self.consume_close_angle(source, iter)?,
 
                        Some(TokenKind::ShiftRight) => self.consume_double_close_angle(source, iter)?,
 
                        Some(TokenKind::CloseParen) => self.consume_close_paren(source, iter)?,
 
                        _ => return Err(ParseError::new_error_str_at_pos(
 
                            source, iter.last_valid_pos(),
 
                            "unexpected token: expected typename, '(', '>', '>>' or ')'"
 
                        ))
 
                    }
 
                }
 
            }
 
        }
 

	
 
        // If here then we have found the correct number of closing braces.
 
        // However we might still have any number of array postfixed
 
        if inside_angular_bracket.is_none() {
 
            while Some(TokenKind::OpenSquare) == iter.next() {
 
                self.consume_square_parens(source, iter)?;
 
            }
 
        }
 

	
 
        // Type should be completed. But we still need to check the polymorphic
 
        // arguments and strip tuples with just one embedded type.
 
        let num_entries = self.entries.len();
 

	
 
        for el_index in 0..num_entries {
 
            let cur_element = &self.entries[el_index];
 

	
 
            // Peek ahead to see how many embedded types we have
 
            let mut encountered_embedded = 0;
 
            for peek_index in el_index + 1..num_entries {
 
                let peek_element = &self.entries[peek_index];
 
                if peek_element.depth == cur_element.depth + 1 {
 
                    encountered_embedded += 1;
 
                } else if peek_element.depth <= cur_element.depth {
 
                    break;
 
                }
 
            }
 

	
 
            // If we're dealing with a tuple then we don't need to determine if
 
            // the number of embedded types is correct, we simply need to set it
 
            // to whatever what was encountered.
 
            if let ParserTypeVariant::Tuple(_) = cur_element.element.variant {
 
                self.entries[el_index].element.variant = ParserTypeVariant::Tuple(encountered_embedded);
 
            } else {
 
                let expected_embedded = cur_element.element.variant.num_embedded() as u32;
 
                if expected_embedded != encountered_embedded {
 
                    if encountered_embedded == 0 {
 
                        // Every polymorphic argument should be inferred
 
                        if !allow_inference {
 
                            return Err(ParseError::new_error_str_at_span(
 
                                source, cur_element.element.element_span,
 
                                "type inference is not allowed here"
 
                            ));
 
                        }
 

	
 
                        // Insert missing types
 
                        let inserted_span = cur_element.element.element_span;
 
                        let inserted_depth = cur_element.depth + 1;
 
                        self.entries.reserve(expected_embedded as usize);
 
                        self.entries.insert(el_index + 1, Entry{
 
                            element: ParserTypeElement{
 
                                element_span: inserted_span,
 
                                variant: ParserTypeVariant::Inferred,
 
                            },
 
                            depth: inserted_depth,
 
                        });
 
                    } else {
 
                        // Mismatch in number of embedded types
 
                        return Err(Self::construct_poly_arg_mismatch_error(
 
                            source, cur_element.element.element_span, allow_inference,
 
                            expected_embedded, encountered_embedded
 
                        ));
 
                    }
 
                }
 
            }
 
        }
 

	
 
        // Convert the results from parsing into the `ParserType`
 
        let mut elements = Vec::with_capacity(self.entries.len());
 
        debug_assert!(!self.entries.is_empty());
 

	
 
        for entry in self.entries.drain(..) {
 
            elements.push(entry.element)
 
@@ -81,45 +259,349 @@ impl ParserTypeParser {
 
        return Ok(ParserType{
 
            elements,
 
            full_span: InputSpan::from_positions(self.first_pos, self.last_pos),
 
        });
 
    }
 

	
 
    /// Consumes an identifier that should resolve to some kind of type. There
 
    /// may be trailing '::' tokens, commas, or polymorphic arguments.
 
    fn consume_parser_type_ident(
 
        &self, iter: &mut TokenIter, symbols: &SymbolTable, poly_vars: &[Identifier],
 
        allow_inference: bool,
 
    ) -> Result<ParserTypeElement, ParserTypeError> {
 
    // --- Parsing Utilities
 

	
 
    #[inline]
 
    fn consume_type_idents(
 
        &mut self, source: &InputSource, heap: &Heap, symbols: &SymbolTable,
 
        wrapping_definition: DefinitionId, poly_vars: &[Identifier],
 
        cur_scope: SymbolScope, allow_inference: bool, iter: &mut TokenIter
 
    ) -> Result<(), ParseError> {
 
        let element = Self::consume_parser_type_element(
 
            iter, source, heap, symbols, wrapping_definition, poly_vars, cur_scope, allow_inference
 
        )?;
 
        let depth = self.cur_depth();
 
        self.last_pos = element.element_span.end;
 
        self.entries.push(Entry{ element, depth });
 
        self.parse_state = ParseState::TypeMaybePolyArgs;
 

	
 
        return Ok(());
 
    }
 

	
 
    #[inline]
 
    fn push_depth(&mut self, kind: DepthKind, pos: InputPosition) {
 
        self.depths.push(DepthElement{ kind, pos });
 
    fn consume_open_angle(&mut self, iter: &mut TokenIter) {
 
        // Note: open angular bracket is only consumed when we just parsed an
 
        //  ident-based type. So the last element of the `entries` array is the
 
        //  one that this angular bracket starts the polymorphic arguments for.
 
        let angle_start_pos = iter.next_start_position();
 
        let entry_index = (self.entries.len() - 1) as u32;
 
        self.push_depth(DepthKind::PolyArgs, entry_index, angle_start_pos);
 
        self.parse_state = ParseState::PolyArgStart;
 

	
 
        iter.consume();
 
    }
 

	
 
    #[inline]
 
    fn consume_close_angle(&mut self, source: &InputSource, iter: &mut TokenIter) -> Result<(), ParseError> {
 
        let (angle_start_pos, angle_end_pos) = iter.next_positions();
 
        self.last_pos = angle_end_pos;
 
        self.pop_depth(source, DepthKind::PolyArgs, angle_start_pos)?;
 
        self.parse_state = ParseState::TypeNeverPolyArgs;
 

	
 
        iter.consume();
 
        return Ok(())
 
    }
 

	
 
    #[inline]
 
    fn pop_depth(&mut self, kind: DepthKind, pos: InputPosition) -> Result<(), ParserTypeError> {
 
    fn consume_double_close_angle(&mut self, source: &InputSource, iter: &mut TokenIter) -> Result<(), ParseError> {
 
        let (angle_start_pos, angle_end_pos) = iter.next_positions();
 
        self.last_pos = angle_end_pos;
 

	
 
        self.pop_depth(source, DepthKind::PolyArgs, angle_start_pos)?; // first '>' in '>>'.
 
        self.pop_depth(source, DepthKind::PolyArgs, angle_start_pos.with_offset(1))?; // second '>' in '>>'
 
        self.parse_state = ParseState::TypeNeverPolyArgs;
 

	
 
        iter.consume(); // consume once, '>>' is one token
 
        return Ok(())
 
    }
 

	
 
    #[inline]
 
    fn consume_open_paren(&mut self, iter: &mut TokenIter) {
 
        let paren_start_pos = iter.next_start_position();
 
        let cur_depth = self.cur_depth();
 
        let entry_index = self.entries.len() as u32;
 
        self.entries.push(Entry{
 
            element: ParserTypeElement {
 
                element_span: InputSpan::from_positions(paren_start_pos, paren_start_pos),
 
                variant: ParserTypeVariant::Tuple(0),
 
            },
 
            depth: cur_depth,
 
        });
 

	
 
        self.push_depth(DepthKind::Tuple, entry_index, paren_start_pos);
 
        self.parse_state = ParseState::TupleStart;
 

	
 
        iter.consume();
 
    }
 

	
 
    #[inline]
 
    fn consume_close_paren(&mut self, source: &InputSource, iter: &mut TokenIter) -> Result<(), ParseError> {
 
        let (paren_start_pos, paren_end_pos) = iter.next_positions();
 
        self.last_pos = paren_end_pos;
 
        let tuple_type_index = self.pop_depth(source, DepthKind::Tuple, paren_start_pos)?;
 
        self.entries[tuple_type_index as usize].element.element_span.end = paren_end_pos.with_offset(1);
 
        self.parse_state = ParseState::TypeNeverPolyArgs;
 

	
 
        iter.consume();
 
        return Ok(())
 
    }
 

	
 
    #[inline]
 
    fn consume_comma(&mut self, iter: &mut TokenIter) {
 
        iter.consume();
 
        self.parse_state = ParseState::ParsedComma;
 
    }
 

	
 
    #[inline]
 
    fn consume_square_parens(&mut self, source: &InputSource, iter: &mut TokenIter) -> Result<(), ParseError> {
 
        // Consume the opening square paren that forms the postfixed array type
 
        let array_start_pos = iter.next_start_position();
 
        iter.consume();
 
        if iter.next() != Some(TokenKind::CloseSquare) {
 
            return Err(ParseError::new_error_str_at_pos(
 
                source, iter.last_valid_pos(),
 
                "unexpected token: expected ']'"
 
            ));
 
        }
 

	
 
        let (_, array_end_pos) = iter.next_positions();
 
        let array_span = InputSpan::from_positions(array_start_pos, array_end_pos);
 
        self.last_pos = array_end_pos;
 

	
 
        // In the language we put the array specification after a type, in the
 
        // type tree we need to make the array type the parent, so:
 
        let insert_depth = self.cur_depth();
 
        let insert_at = self.entries.iter().rposition(|e| e.depth == insert_depth).unwrap();
 
        let num_embedded = self.entries[insert_at].element.variant.num_embedded();
 

	
 
        self.entries.insert(insert_at, Entry{
 
            element: ParserTypeElement{
 
                element_span: array_span,
 
                variant: ParserTypeVariant::Array,
 
            },
 
            depth: insert_depth
 
        });
 

	
 
        // Need to increment the depth of the child types
 
        self.entries[insert_at + 1].depth += 1; // element we applied the array type to
 
        if num_embedded != 0 {
 
            for index in insert_at + 2..self.entries.len() {
 
                let element = &mut self.entries[index];
 
                if element.depth >= insert_depth + 1 {
 
                    element.depth += 1;
 
                } else {
 
                    break;
 
                }
 
            }
 
        }
 

	
 
        return Ok(())
 
    }
 

	
 
    /// Consumes a namespaced identifier that should resolve to some kind of
 
    /// type. There may be commas or polymorphic arguments remaining after this
 
    /// function has finished.
 
    fn consume_parser_type_element(
 
        iter: &mut TokenIter, source: &InputSource, heap: &Heap, symbols: &SymbolTable,
 
        wrapping_definition: DefinitionId, poly_vars: &[Identifier],
 
        mut scope: SymbolScope, allow_inference: bool,
 
    ) -> Result<ParserTypeElement, ParseError> {
 
        use ParserTypeVariant as PTV;
 
        let (mut type_text, mut type_span) = consume_any_ident(source, iter)?;
 

	
 
        let variant = match type_text {
 
            KW_TYPE_MESSAGE => PTV::Message,
 
            KW_TYPE_BOOL => PTV::Bool,
 
            KW_TYPE_UINT8 => PTV::UInt8,
 
            KW_TYPE_UINT16 => PTV::UInt16,
 
            KW_TYPE_UINT32 => PTV::UInt32,
 
            KW_TYPE_UINT64 => PTV::UInt64,
 
            KW_TYPE_SINT8 => PTV::SInt8,
 
            KW_TYPE_SINT16 => PTV::SInt16,
 
            KW_TYPE_SINT32 => PTV::SInt32,
 
            KW_TYPE_SINT64 => PTV::SInt64,
 
            KW_TYPE_IN_PORT => PTV::Input,
 
            KW_TYPE_OUT_PORT => PTV::Output,
 
            KW_TYPE_CHAR => PTV::Character,
 
            KW_TYPE_STRING => PTV::String,
 
            KW_TYPE_INFERRED => {
 
                if !allow_inference {
 
                    return Err(ParseError::new_error_str_at_span(
 
                        source, type_span, "type inference is not allowed here"
 
                    ));
 
                }
 

	
 
                PTV::Inferred
 
            },
 
            _ => {
 
                // Must be some kind of symbolic type
 
                let mut type_kind = None;
 
                for (poly_idx, poly_var) in poly_vars.iter().enumerate() {
 
                    if poly_var.value.as_bytes() == type_text {
 
                        type_kind = Some(PTV::PolymorphicArgument(wrapping_definition, poly_idx as u32));
 
                    }
 
                }
 

	
 
                if type_kind.is_none() {
 
                    // Check symbol table for definition. To be fair, the language
 
                    // only allows a single namespace for now. That said:
 
                    let last_symbol = symbols.get_symbol_by_name(scope, type_text);
 
                    if last_symbol.is_none() {
 
                        return Err(ParseError::new_error_str_at_span(
 
                            source, type_span, "unknown type"
 
                        ));
 
                    }
 
                    let mut last_symbol = last_symbol.unwrap();
 

	
 
                    // Resolving scopes until we reach the intended type
 
                    loop {
 
                        match &last_symbol.variant {
 
                            SymbolVariant::Module(symbol_module) => {
 
                                // Expecting more identifiers
 
                                if Some(TokenKind::ColonColon) != iter.next() {
 
                                    return Err(ParseError::new_error_str_at_span(
 
                                        source, type_span, "expected a type but got a module"
 
                                    ));
 
                                }
 

	
 
                                consume_token(source, iter, TokenKind::ColonColon)?;
 

	
 
                                // Consume next part of type and prepare for next
 
                                // lookup loop
 
                                let (next_text, next_span) = consume_any_ident(source, iter)?;
 
                                let old_text = type_text;
 
                                type_text = next_text;
 
                                type_span.end = next_span.end;
 
                                scope = SymbolScope::Module(symbol_module.root_id);
 

	
 
                                let new_symbol = symbols.get_symbol_by_name_defined_in_scope(scope, type_text);
 
                                if new_symbol.is_none() {
 
                                    // If the type is imported in the module then notify the programmer
 
                                    // that imports do not leak outside of a module
 
                                    let type_name = String::from_utf8_lossy(type_text);
 
                                    let module_name = String::from_utf8_lossy(old_text);
 
                                    let suffix = if symbols.get_symbol_by_name(scope, type_text).is_some() {
 
                                        format!(
 
                                            ". The module '{}' does import '{}', but these imports are not visible to other modules",
 
                                            &module_name, &type_name
 
                                        )
 
                                    } else {
 
                                        String::new()
 
                                    };
 

	
 
                                    let message = format!("unknown type '{}' in module '{}'{}", type_name, module_name, suffix);
 
                                    return Err(ParseError::new_error_at_span(source, next_span, message));
 
                                }
 

	
 
                                last_symbol = new_symbol.unwrap();
 
                            },
 
                            SymbolVariant::Definition(symbol_definition) => {
 
                                let num_poly_vars = heap[symbol_definition.definition_id].poly_vars().len();
 
                                type_kind = Some(PTV::Definition(symbol_definition.definition_id, num_poly_vars as u32));
 
                                break;
 
                            }
 
                        }
 
                    }
 
                }
 

	
 
                debug_assert!(type_kind.is_some());
 
                type_kind.unwrap()
 
            },
 
        };
 

	
 
        Ok(ParserTypeElement{ element_span: type_span, variant })
 
    }
 

	
 
    // --- Parsing Depth Management
 

	
 
    #[inline]
 
    fn push_depth(&mut self, kind: DepthKind, entry_index: u32, pos: InputPosition) {
 
        self.depths.push(DepthElement{ kind, entry_index, pos });
 
    }
 

	
 
    #[inline]
 
    fn pop_depth(&mut self, source: &InputSource, kind: DepthKind, pos: InputPosition) -> Result<u32, ParseError> {
 
        if self.depths.is_empty() {
 
            // More closing parens than opening ones
 
            let message = match kind {
 
                DepthKind::Tuple => "unmatched ')'",
 
                DepthKind::PolyArgs => "unmatched '>'",
 
            };
 
            return Err(ParserTypeError::MessageAt(pos, message))
 
            return Err(ParseError::new_error_str_at_pos(source, pos, message))
 
        }
 

	
 
        let last = *self.depths.last().unwrap();
 
        if last != kind {
 
            // Wrong kind of paren
 
            let (message_second) = match kind {
 
                DepthKind::Tuple => "unexpected closing"
 
            }
 
        let last = self.depths.last().unwrap();
 
        if last.kind != kind {
 
            // Wrong kind of closing parens
 
            let (encountered_message, matching_message) = match kind {
 
                DepthKind::Tuple => (
 
                    "unexpected closing ')'",
 
                    "expected a '>' to match this '<'"
 
                ),
 
                DepthKind::PolyArgs => (
 
                    "unexpected closing '>'",
 
                    "expected a ')' to match this '('"
 
                ),
 
            };
 

	
 
            return Err(
 
                ParseError::new_error_str_at_pos(source, pos, encountered_message)
 
                    .with_info_str_at_pos(source, last.pos, matching_message)
 
            );
 
        }
 

	
 
        let popped = self.depths.pop().unwrap();
 
        return Ok(popped.entry_index);
 
    }
 

	
 
    #[inline]
 
    fn cur_depth(&self) -> i32 {
 
        return self.depths.len() as i32;
 
    }
 

	
 
    // --- Small Utilities
 

	
 
    fn construct_poly_arg_mismatch_error(
 
        source: &InputSource, span: InputSpan, allow_inference: bool,
 
        num_expected: u32, num_encountered: u32
 
    ) -> ParseError {
 
        let type_name = String::from_utf8_lossy(source.section_at_span(span));
 

	
 
        fn polymorphic_name_text(num: u32) -> &'static str {
 
            if num == 1 { "polymorphic argument" } else { "polymorphic arguments" }
 
        }
 
        fn were_or_was(num: u32) -> &'static str {
 
            if num == 1 { "was" } else { "were" }
 
        }
 

	
 
        if num_expected == 0 {
 
            return ParseError::new_error_at_span(
 
                source, span,
 
                format!(
 
                    "the type '{}' is not polymorphic, yet {} {} {} provided",
 
                    type_name, num_encountered, polymorphic_name_text(num_encountered),
 
                    were_or_was(num_encountered)
 
                )
 
            );
 
        }
 

	
 
        let maybe_infer_text = if allow_inference {
 
            " (or none, to perform implicit type inference)"
 
        } else {
 
            ""
 
        };
 

	
 
        return ParseError::new_error_at_span(
 
            source, span,
 
            format!(
 
                "expected {} {}{} for the type '{}', but {} {} provided",
 
                num_expected, polymorphic_name_text(num_expected),
 
                maybe_infer_text, type_name, num_encountered,
 
                were_or_was(num_encountered)
 
            )
 
        );
 
    }
 
}
 
\ No newline at end of file
0 comments (0 inline, 0 general)