Files @ 3381d0627372
Branch filter:

Location: CSY/reowolf/src/protocol/parser/utils.rs

3381d0627372 3.9 KiB application/rls-services+xml Show Annotation Show as Raw Download as Raw
MH
WIP on struct field access inference
use crate::protocol::ast::*;
use crate::protocol::inputsource::*;
use super::symbol_table::*;
use super::type_table::*;

/// Utility result type.
pub(crate) enum FindTypeResult<'t, 'i> {
    // Found the type exactly
    Found(&'t DefinedType),
    // Could not match symbol
    SymbolNotFound{ident_pos: InputPosition},
    // Matched part of the namespaced identifier, but not completely
    SymbolPartial{ident_pos: InputPosition, symbol_pos: InputPosition, ident_iter: NamespacedIdentifierIter<'i>},
    // Symbol matched, but points to a namespace/module instead of a type
    SymbolNamespace{ident_pos: InputPosition, symbol_pos: InputPosition},
}

// TODO: @cleanup Find other uses of this pattern
impl<'t, 'i> FindTypeResult<'t, 'i> {
    /// Utility function to transform the `FindTypeResult` into a `Result` where
    /// `Ok` contains the resolved type, and `Err` contains a `ParseError` which
    /// can be readily returned. This is the most common use.
    pub(crate) fn as_parse_error(self, module_source: &InputSource) -> Result<&'t DefinedType, ParseError2> {
        match self {
            FindTypeResult::Found(defined_type) => Ok(defined_type),
            FindTypeResult::SymbolNotFound{ident_pos} => {
                Err(ParseError2::new_error(
                    module_source, ident_pos,
                    "Could not resolve this identifier to a symbol"
                ))
            },
            FindTypeResult::SymbolPartial{ident_pos, symbol_pos, ident_iter} => {
                Err(ParseError2::new_error(
                    module_source, ident_pos, 
                    "Could not fully resolve this identifier to a symbol"
                ).with_postfixed_info(
                    module_source, symbol_pos, 
                    &format!(
                        "The partial identifier '{}' was matched to this symbol",
                        String::from_utf8_lossy(ident_iter.returned_section()),
                    )
                ))
            },
            FindTypeResult::SymbolNamespace{ident_pos, symbol_pos} => {
                Err(ParseError2::new_error(
                    module_source, ident_pos,
                    "This identifier was resolved to a namespace instead of a type"
                ).with_postfixed_info(
                    module_source, symbol_pos,
                    "This is the referenced namespace"
                ))
            }
        }
    }
}

/// Attempt to find the type pointer to by a (root, identifier) combination. The
/// type must match exactly (no parts in the namespace iterator remaining) and
/// must be a type, not a namespace. 
pub(crate) fn find_type_definition<'t, 'i>(
    symbols: &SymbolTable, types: &'t TypeTable, 
    root_id: RootId, identifier: &'i NamespacedIdentifier
) -> FindTypeResult<'t, 'i> {
    // Lookup symbol
    let symbol = symbols.resolve_namespaced_symbol(root_id, identifier);
    if symbol.is_none() { 
        return FindTypeResult::SymbolNotFound{ident_pos: identifier.position};
    }
    
    // Make sure we resolved it exactly
    let (symbol, ident_iter) = symbol.unwrap();
    if ident_iter.num_remaining() != 0 { 
        return FindTypeResult::SymbolPartial{
            ident_pos: identifier.position, 
            symbol_pos: symbol.position, 
            ident_iter
        };
    }

    match symbol.symbol {
        Symbol::Namespace(_) => {
            FindTypeResult::SymbolNamespace{
                ident_pos: identifier.position, 
                symbol_pos: symbol.position
            }
        },
        Symbol::Definition((_, definition_id)) => {
            // If this function is called correctly, then we should always be
            // able to match the definition's ID to an entry in the type table.
            let definition = types.get_base_definition(&definition_id);
            debug_assert!(definition.is_some());
            FindTypeResult::Found(definition.unwrap())
        }
    }
}