Files @ fcf8c30ed335
Branch filter:

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

fcf8c30ed335 6.9 KiB application/rls-services+xml Show Source Show as Raw Download as Raw
mh
WIP on fixing type inferencer
b0a907fd8513
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
19b752d30f04
cd546710a6c9
cd546710a6c9
cd546710a6c9
19b752d30f04
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
1811fe09856a
f7c20c8ac012
f7c20c8ac012
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
c87205ed6292
cd546710a6c9
cd546710a6c9
cd546710a6c9
c87205ed6292
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
b0a907fd8513
c87205ed6292
cd546710a6c9
cd546710a6c9
b0a907fd8513
b0a907fd8513
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
c87205ed6292
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
19b752d30f04
cd546710a6c9
cd546710a6c9
28df9835906f
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
28df9835906f
cd546710a6c9
cd546710a6c9
b0a907fd8513
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
cd546710a6c9
28df9835906f
cd546710a6c9
cd546710a6c9
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
19b752d30f04
28df9835906f
28df9835906f
28df9835906f
c87205ed6292
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
c87205ed6292
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
c87205ed6292
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
19b752d30f04
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
28df9835906f
cd546710a6c9
    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, NamespacedIdentifierIter<'i>)),
    // Could not match symbol
    SymbolNotFound{ident_pos: InputPosition},
    // Matched part of the namespaced identifier, but not completely
    SymbolPartial{ident_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
// TODO: Hindsight is 20/20: this belongs in the visitor_linker, not in a 
//  separate file.
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, NamespacedIdentifierIter<'i>), ParseError> {
        match self {
            FindTypeResult::Found(defined_type) => Ok(defined_type),
            FindTypeResult::SymbolNotFound{ident_pos} => {
                Err(ParseError::new_error(
                    module_source, ident_pos,
                    "Could not resolve this identifier to a symbol"
                ))
            },
            FindTypeResult::SymbolPartial{ident_pos, ident_iter} => {
                Err(ParseError::new_error(
                    module_source, ident_pos, 
                    &format!(
                        "Could not fully resolve this identifier to a symbol, was only able to match '{}'",
                        &String::from_utf8_lossy(ident_iter.returned_section())
                    )
                ))
            },
            FindTypeResult::SymbolNamespace{ident_pos, symbol_pos} => {
                Err(ParseError::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, ident_iter) = symbols.resolve_namespaced_identifier(root_id, identifier);
    if symbol.is_none() { 
        return FindTypeResult::SymbolNotFound{ident_pos: identifier.position};
    }
    
    // Make sure we resolved it exactly
    let symbol = symbol.unwrap();
    if ident_iter.num_remaining() != 0 { 
        return FindTypeResult::SymbolPartial{
            ident_pos: identifier.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(), ident_iter))
        }
    }
}

pub(crate) enum MatchPolymorphResult<'t> {
    Matching,
    InferAll(usize),
    Mismatch{defined_type: &'t DefinedType, ident_position: InputPosition, num_specified: usize},
    NoneExpected{defined_type: &'t DefinedType, ident_position: InputPosition},
}

impl<'t> MatchPolymorphResult<'t> {
    pub(crate) fn as_parse_error(self, heap: &Heap, module_source: &InputSource) -> Result<usize, ParseError> {
        match self {
            MatchPolymorphResult::Matching => Ok(0),
            MatchPolymorphResult::InferAll(count) => {
                debug_assert!(count > 0);
                Ok(count)
            },
            MatchPolymorphResult::Mismatch{defined_type, ident_position, num_specified} => {
                let type_identifier = heap[defined_type.ast_definition].identifier();
                let args_name = if defined_type.poly_vars.len() == 1 {
                    "argument"
                } else {
                    "arguments"
                };

                return Err(ParseError::new_error(
                    module_source, ident_position,
                    &format!(
                        "expected {} polymorphic {} (or none, to infer them) for the type {}, but {} were specified",
                        defined_type.poly_vars.len(), args_name, 
                        &String::from_utf8_lossy(&type_identifier.value),
                        num_specified
                    )
                ))
            },
            MatchPolymorphResult::NoneExpected{defined_type, ident_position, ..} => {
                let type_identifier = heap[defined_type.ast_definition].identifier();
                return Err(ParseError::new_error(
                    module_source, ident_position,
                    &format!(
                        "the type {} is not polymorphic",
                        &String::from_utf8_lossy(&type_identifier.value)
                    )
                ))
            }
        }
    }
}

/// Attempt to match the polymorphic arguments to the number of polymorphic
/// variables in the definition.
pub(crate) fn match_polymorphic_args_to_vars<'t>(
    defined_type: &'t DefinedType, poly_args: Option<&[ParserTypeId]>, ident_position: InputPosition
) -> MatchPolymorphResult<'t> {
    if defined_type.poly_vars.is_empty() {
        // No polymorphic variables on type
        if poly_args.is_some() {
            return MatchPolymorphResult::NoneExpected{
                defined_type,
                ident_position, 
            };
        }
    } else {
        // Polymorphic variables on type
        let has_specified = poly_args.map_or(false, |a| a.len() != 0);
        if !has_specified {
            // Implicitly infer all of the polymorphic arguments
            return MatchPolymorphResult::InferAll(defined_type.poly_vars.len());
        }

        let num_specified = poly_args.unwrap().len();
        if num_specified != defined_type.poly_vars.len() {
            return MatchPolymorphResult::Mismatch{
                defined_type,
                ident_position,
                num_specified,
            };
        }
    }

    MatchPolymorphResult::Matching
}