Changeset - 2d6659928698
[Not reviewed]
0 5 0
MH - 4 years ago 2021-04-01 10:25:35
henger@cwi.nl
more refactoring of namespaced identifier
5 files changed with 133 insertions and 62 deletions:
0 comments (0 inline, 0 general)
src/protocol/ast.rs
Show inline comments
 
@@ -578,35 +578,35 @@ impl SyntaxElement for Import {
 
            Import::Module(m) => m.position,
 
            Import::Symbols(m) => m.position
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub struct ImportModule {
 
    pub this: ImportId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub module_name: Vec<u8>,
 
    pub alias: Vec<u8>,
 
    pub alias: Identifier,
 
    // Phase 2: module resolving
 
    pub module_id: Option<RootId>,
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub struct AliasedSymbol {
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub name: Vec<u8>,
 
    pub alias: Vec<u8>,
 
    pub name: Identifier,
 
    pub alias: Identifier,
 
    // Phase 2: symbol resolving
 
    pub definition_id: Option<DefinitionId>,
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub struct ImportSymbols {
 
    pub this: ImportId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub module_name: Vec<u8>,
 
    // Phase 2: module resolving
 
    pub module_id: Option<RootId>,
 
@@ -635,66 +635,74 @@ impl PartialEq<NamespacedIdentifier> for Identifier {
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub enum NamespacedIdentifierPart {
 
    // Regular identifier
 
    Identifier{start: u16, end: u16},
 
    // Polyargs associated with a preceding identifier
 
    PolyArgs{start: u16, end: u16},
 
}
 

	
 
impl NamespacedIdentifierPart {
 
    fn is_identifier(&self) -> bool {
 
    pub(crate) fn is_identifier(&self) -> bool {
 
        match self {
 
            NamespacedIdentifierPart::Identifier{..} => true,
 
            NamespacedIdentifierPart::PolyArgs{..} => false,
 
        }
 
    }
 

	
 
    fn as_identifier(&self) -> (u16, u16) {
 
    pub(crate) fn as_identifier(&self) -> (u16, u16) {
 
        match self {
 
            NamespacedIdentifierPart::Identifier{start, end} => (*start, *end),
 
            NamespacedIdentifierPart::PolyArgs{..} => {
 
                unreachable!("Tried to obtain {:?} as Identifier", self);
 
            }
 
        }
 
    }
 

	
 
    fn as_poly_args(&self) -> (u16, u16) {
 
    pub(crate) fn as_poly_args(&self) -> (u16, u16) {
 
        match self {
 
            NamespacedIdentifierPart::PolyArgs{start, end} => (*start, *end),
 
            NamespacedIdentifierPart::Identifier{..} => {
 
                unreachable!("Tried to obtain {:?} as PolyArgs", self)
 
            }
 
        }
 
    }
 
}
 

	
 
/// An identifier with optional namespaces and polymorphic variables
 
/// An identifier with optional namespaces and polymorphic variables. Note that 
 
/// we allow each identifier to be followed by polymorphic arguments during the 
 
/// parsing phase (e.g. Foo<A,B>::Bar<C,D>::Qux). But in our current language 
 
/// implementation we can only have valid namespaced identifier that contain one
 
/// set of polymorphic arguments at the appropriate position.
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub struct NamespacedIdentifier2 {
 
    pub position: InputPosition,
 
    pub value: Vec<u8>, // Full name as it resides in the input source
 
    pub poly_args: Vec<ParserTypeId>, // All poly args littered throughout the namespaced identifier
 
    pub parts: Vec<NamespacedIdentifierPart>, // Indices into value/poly_args
 
}
 

	
 
impl NamespacedIdentifier2 {
 
    pub fn iter(&self) -> NamespacedIdentifier2Iter {
 
        return NamespacedIdentifier2Iter{
 
            identifier: self,
 
            element_idx: 0
 
        }
 
    }
 

	
 
    pub fn has_poly_args(&self) -> bool {
 
        return !self.poly_args.is_empty();
 
    }
 
}
 

	
 
impl PartialEq for NamespacedIdentifier2 {
 
    fn eq(&self, other: &Self) -> bool {
 
        return self.value == other.value
 
    }
 
}
 

	
 
impl PartialEq<Identifier> for NamespacedIdentifier2 {
 
    fn eq(&self, other: &Identifier) -> bool {
 
        return self.value == other.value
 
    }
src/protocol/lexer.rs
Show inline comments
 
@@ -2385,72 +2385,74 @@ impl Lexer<'_> {
 
        }
 
    }
 

	
 
    fn has_import(&self) -> bool {
 
        self.has_keyword(b"import")
 
    }
 
    fn consume_import(&mut self, h: &mut Heap) -> Result<ImportId, ParseError2> {
 
        // Parse the word "import" and the name of the module
 
        let position = self.source.pos();
 
        self.consume_keyword(b"import")?;
 
        self.consume_whitespace(true)?;
 
        let mut value = Vec::new();
 
        let mut last_ident_pos = self.source.pos();
 
        let mut ident = self.consume_ident()?;
 
        value.append(&mut ident);
 
        let mut last_ident_start = 0;
 

	
 
        while self.has_string(b".") {
 
            self.consume_string(b".")?;
 
            value.push(b'.');
 
            last_ident_pos = self.source.pos();
 
            ident = self.consume_ident()?;
 
            last_ident_start = value.len();
 
            value.append(&mut ident);
 
        }
 

	
 

	
 
        self.consume_whitespace(false)?;
 

	
 
        // Check for the potential aliasing or specific module imports
 
        let import = if self.has_string(b"as") {
 
            self.consume_string(b"as")?;
 
            self.consume_whitespace(true)?;
 
            let alias = self.consume_ident()?;
 
            let alias = self.consume_identifier()?;
 

	
 
            h.alloc_import(|this| Import::Module(ImportModule{
 
                this,
 
                position,
 
                module_name: value,
 
                alias,
 
                module_id: None,
 
            }))
 
        } else if self.has_string(b"::") {
 
            self.consume_string(b"::")?;
 
            self.consume_whitespace(false)?;
 

	
 
            let next = self.source.next();
 
            if Some(b'{') == next {
 
                let symbols = match self.consume_comma_separated(
 
                    h, b'{', b'}', "Expected end of import list",
 
                    |lexer, _heap| {
 
                        // Symbol name
 
                        let position = lexer.source.pos();
 
                        let name = lexer.consume_ident()?;
 
                        let name = lexer.consume_identifier()?;
 
                        lexer.consume_whitespace(false)?;
 

	
 
                        // Symbol alias
 
                        if lexer.has_string(b"as") {
 
                            // With alias
 
                            lexer.consume_string(b"as")?;
 
                            lexer.consume_whitespace(true)?;
 
                            let alias = lexer.consume_ident()?;
 
                            let alias = lexer.consume_identifier()?;
 

	
 
                            Ok(AliasedSymbol{
 
                                position,
 
                                name,
 
                                alias,
 
                                definition_id: None
 
                            })
 
                        } else {
 
                            // Without alias
 
                            Ok(AliasedSymbol{
 
                                position,
 
                                name: name.clone(),
 
@@ -2473,57 +2475,60 @@ impl Lexer<'_> {
 
                }))
 
            } else if Some(b'*') == next {
 
                self.source.consume();
 
                h.alloc_import(|this| Import::Symbols(ImportSymbols{
 
                    this,
 
                    position,
 
                    module_name: value,
 
                    module_id: None,
 
                    symbols: Vec::new()
 
                }))
 
            } else if self.has_identifier() {
 
                let position = self.source.pos();
 
                let name = self.consume_ident()?;
 
                let name = self.consume_identifier()?;
 
                self.consume_whitespace(false)?;
 
                let alias = if self.has_string(b"as") {
 
                    self.consume_string(b"as")?;
 
                    self.consume_whitespace(true)?;
 
                    self.consume_ident()?
 
                    self.consume_identifier()?
 
                } else {
 
                    name.clone()
 
                };
 

	
 
                h.alloc_import(|this| Import::Symbols(ImportSymbols{
 
                    this,
 
                    position,
 
                    module_name: value,
 
                    module_id: None,
 
                    symbols: vec![AliasedSymbol{
 
                        position,
 
                        name,
 
                        alias,
 
                        definition_id: None
 
                    }]
 
                }))
 
            } else {
 
                return Err(self.error_at_pos("Expected '*', '{' or a symbol name"));
 
            }
 
        } else {
 
            // No explicit alias or subimports, so implicit alias
 
            let alias = Vec::from(&value[last_ident_start..]);
 
            let alias_value = Vec::from(&value[last_ident_start..]);
 
            h.alloc_import(|this| Import::Module(ImportModule{
 
                this,
 
                position,
 
                module_name: value,
 
                alias,
 
                alias: Identifier{
 
                    position: last_ident_pos,
 
                    value: Vec::from(alias_value),
 
                },
 
                module_id: None,
 
            }))
 
        };
 

	
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b";")?;
 
        Ok(import)
 
    }
 
    pub fn consume_protocol_description(&mut self, h: &mut Heap) -> Result<RootId, ParseError2> {
 
        let position = self.source.pos();
 
        let mut pragmas = Vec::new();
 
        let mut imports = Vec::new();
src/protocol/parser/symbol_table.rs
Show inline comments
 
@@ -8,24 +8,47 @@
 
use crate::protocol::ast::*;
 
use crate::protocol::inputsource::*;
 

	
 
use std::collections::{HashMap, hash_map::Entry};
 
use crate::protocol::parser::LexedModule;
 

	
 
#[derive(PartialEq, Eq, Hash)]
 
struct SymbolKey {
 
    module_id: RootId,
 
    symbol_name: Vec<u8>,
 
}
 

	
 
impl SymbolKey {
 
    fn from_identifier(module_id: RootId, symbol: &Identifier) -> Self {
 
        Self{ module_id, symbol_name: symbol.value.clone() }
 
    }
 

	
 
    fn from_namespaced_identifier(module_id: RootId, symbol: &NamespacedIdentifier2) -> Self {
 
        // Strip polymorpic arguments from the identifier
 
        let symbol_name = Vec::with_capacity(symbol.value.len());
 
        debug_assert!(symbol.parts.len() > 0 && symbol.parts[0].is_identifier());
 

	
 
        let mut iter = symbol.iter();
 
        let (first_ident, _) = iter.next().unwrap();
 
        symbol_name.extend(first_ident);
 

	
 
        for (ident, _) in iter {
 
            symbol_name.push(b':');
 
            symbol_name.extend(ident);
 
        }
 

	
 
        Self{ module_id, symbol_name }
 
    }
 
}
 

	
 
pub(crate) enum Symbol {
 
    Namespace(RootId),
 
    Definition((RootId, DefinitionId)),
 
}
 

	
 
pub(crate) struct SymbolValue {
 
    // Position is the place where the symbol is introduced to a module (this
 
    // position always corresponds to the module whose RootId is stored in the
 
    // `SymbolKey` associated with this `SymbolValue`). For a definition this
 
    // is the position where the symbol is defined, for an import this is the
 
    // position of the import statement.
 
    pub(crate) position: InputPosition,
 
@@ -135,25 +158,25 @@ impl SymbolTable {
 

	
 
        self.symbol_lookup.reserve(lookup_reserve_size);
 

	
 
        // First pass: we go through all of the modules and add lookups to
 
        // symbols that are defined within that module. Cross-module imports are
 
        // not yet resolved
 
        for module in modules {
 
            let root = &heap[module.root_id];
 
            for definition_id in &root.definitions {
 
                let definition = &heap[*definition_id];
 
                let identifier = definition.identifier();
 
                if let Err(previous_position) = self.add_definition_symbol(
 
                    module.root_id, identifier.position, &identifier.value,
 
                    identifier.position, SymbolKey::from_identifier(module.root_id, &identifier),
 
                    module.root_id, *definition_id
 
                ) {
 
                    return Err(
 
                        ParseError2::new_error(&module.source, definition.position(), "Symbol is multiply defined")
 
                            .with_postfixed_info(&module.source, previous_position, "Previous definition was here")
 
                    )
 
                }
 
            }
 
        }
 

	
 
        // Second pass: now that we can find symbols in modules, we can resolve
 
        // all imports (if they're correct, that is)
 
@@ -166,26 +189,26 @@ impl SymbolTable {
 
                        // Find the module using its name
 
                        let target_root_id = self.resolve_module(&import.module_name);
 
                        if target_root_id.is_none() {
 
                            return Err(ParseError2::new_error(&module.source, import.position, "Could not resolve module"));
 
                        }
 
                        let target_root_id = target_root_id.unwrap();
 
                        if target_root_id == module.root_id {
 
                            return Err(ParseError2::new_error(&module.source, import.position, "Illegal import of self"));
 
                        }
 

	
 
                        // Add the target module under its alias
 
                        if let Err(previous_position) = self.add_namespace_symbol(
 
                            module.root_id, import.position,
 
                            &import.alias, target_root_id
 
                            import.position, SymbolKey::from_identifier(module.root_id, &import.alias),
 
                            target_root_id
 
                        ) {
 
                            return Err(
 
                                ParseError2::new_error(&module.source, import.position, "Symbol is multiply defined")
 
                                    .with_postfixed_info(&module.source, previous_position, "Previous definition was here")
 
                            );
 
                        }
 
                    },
 
                    Import::Symbols(import) => {
 
                        // Find the target module using its name
 
                        let target_root_id = self.resolve_module(&import.module_name);
 
                        if target_root_id.is_none() {
 
                            return Err(ParseError2::new_error(&module.source, import.position, "Could not resolve module of symbol imports"));
 
@@ -193,25 +216,25 @@ impl SymbolTable {
 
                        let target_root_id = target_root_id.unwrap();
 
                        if target_root_id == module.root_id {
 
                            return Err(ParseError2::new_error(&module.source, import.position, "Illegal import of self"));
 
                        }
 

	
 
                        // Determine which symbols to import
 
                        if import.symbols.is_empty() {
 
                            // Import of all symbols, not using any aliases
 
                            for definition_id in &heap[target_root_id].definitions {
 
                                let definition = &heap[*definition_id];
 
                                let identifier = definition.identifier();
 
                                if let Err(previous_position) = self.add_definition_symbol(
 
                                    module.root_id, import.position, &identifier.value,
 
                                    import.position, SymbolKey::from_identifier(module.root_id, identifier),
 
                                    target_root_id, *definition_id
 
                                ) {
 
                                    return Err(
 
                                        ParseError2::new_error(
 
                                            &module.source, import.position,
 
                                            &format!("Imported symbol '{}' is already defined", String::from_utf8_lossy(&identifier.value))
 
                                        )
 
                                        .with_postfixed_info(
 
                                            &modules[target_root_id.index as usize].source,
 
                                            definition.position(),
 
                                            "The imported symbol is defined here"
 
                                        )
 
@@ -223,25 +246,26 @@ impl SymbolTable {
 
                            }
 
                        } else {
 
                            // Import of specific symbols, optionally using aliases
 
                            for symbol in &import.symbols {
 
                                // Because we have already added per-module definitions, we can use
 
                                // the table to lookup this particular symbol. Note: within a single
 
                                // module a namespace-import and a symbol-import may not collide.
 
                                // Hence per-module symbols are unique.
 
                                // However: if we import a symbol from another module, we don't want
 
                                // to "import a module's imported symbol". And so if we do find
 
                                // a symbol match, we need to make sure it is a definition from
 
                                // within that module by checking `source_root_id == target_root_id`
 
                                let target_symbol = self.resolve_symbol(target_root_id, &symbol.name);
 
                                let key = SymbolKey::from_identifier(target_root_id, &symbol.name);
 
                                let target_symbol = self.symbol_lookup.get(&key);
 
                                let symbol_definition_id = match target_symbol {
 
                                    Some(target_symbol) => {
 
                                        match target_symbol.symbol {
 
                                            Symbol::Definition((symbol_root_id, symbol_definition_id)) => {
 
                                                if symbol_root_id == target_root_id {
 
                                                    Some(symbol_definition_id)
 
                                                } else {
 
                                                    // This is imported within the target module, and not
 
                                                    // defined within the target module
 
                                                    None
 
                                                }
 
                                            },
 
@@ -253,25 +277,25 @@ impl SymbolTable {
 
                                    },
 
                                    None => None
 
                                };
 

	
 
                                if symbol_definition_id.is_none() {
 
                                    return Err(
 
                                        ParseError2::new_error(&module.source, symbol.position, "Could not resolve symbol")
 
                                    )
 
                                }
 
                                let symbol_definition_id = symbol_definition_id.unwrap();
 

	
 
                                if let Err(previous_position) = self.add_definition_symbol(
 
                                    module.root_id, symbol.position, &symbol.alias,
 
                                    symbol.position, SymbolKey::from_identifier(module.root_id, &symbol.alias),
 
                                    target_root_id, symbol_definition_id
 
                                ) {
 
                                    return Err(
 
                                        ParseError2::new_error(&module.source, symbol.position, "Symbol is multiply defined")
 
                                            .with_postfixed_info(&module.source, previous_position, "Previous definition was here")
 
                                    )
 
                                }
 
                            }
 
                        }
 
                    }
 
                }
 
            }
 
@@ -293,129 +317,130 @@ impl SymbolTable {
 
        debug_assert_eq!(
 
            self.symbol_lookup.len(), lookup_reserve_size,
 
            "miscalculated reserved size for symbol lookup table"
 
        );
 
        Ok(())
 
    }
 

	
 
    /// Resolves a module by its defined name
 
    pub(crate) fn resolve_module(&self, identifier: &Vec<u8>) -> Option<RootId> {
 
        self.module_lookup.get(identifier).map(|v| *v)
 
    }
 

	
 
    /// Resolves a symbol within a particular module, indicated by its RootId,
 
    /// with a single non-namespaced identifier
 
    pub(crate) fn resolve_symbol(&self, within_module_id: RootId, identifier: &Vec<u8>) -> Option<&SymbolValue> {
 
        self.symbol_lookup.get(&SymbolKey{ module_id: within_module_id, symbol_name: identifier.clone() })
 
    }
 

	
 
    /// Resolves a namespaced symbol. This method will go as far as possible in
 
    /// going to the right symbol. It will halt the search when:
 
    /// 1. Polymorphic arguments are encountered on the identifier.
 
    /// 2. A non-namespace symbol is encountered.
 
    /// 3. A part of the identifier couldn't be resolved to anything
 
    /// The returned iterator will always point to the next symbol (even if 
 
    /// nothing was found)
 
    pub(crate) fn resolve_namespaced_symbol<'t, 'i>(
 
        &'t self, root_module_id: RootId, identifier: &'i NamespacedIdentifier2
 
    ) -> (Option<&'t Symbol>, &'i NamespacedIdentifier2Iter) {
 
    ) -> (Option<&'t SymbolValue>, NamespacedIdentifier2Iter<'i>) {
 
        let mut iter = identifier.iter();
 
        let mut symbol: Option<&SymbolValue> = None;
 
        let mut within_module_id = root_module_id;
 

	
 
        while let Some((partial, poly_args)) = iter.next() {
 
            // Lookup the symbol within the currently iterated upon module
 
            let lookup_key = SymbolKey{ module_id: within_module_id, symbol_name: Vec::from(partial) };
 
            let new_symbol = self.symbol_lookup.get(&lookup_key);
 
            
 
            match new_symbol {
 
                None => {
 
                    // Can't find anything
 
                    symbol = None;
 
                    break;
 
                },
 
                Some(new_symbol) => {
 
                    // Found something, but if we already moved to another
 
                    // module then we don't want to keep jumping across modules,
 
                    // we're only interested in symbols defined within that
 
                    // module.
 
                    match &new_symbol.symbol {
 
                        Symbol::Namespace(new_root_id) => {
 
                            if root_module_id != within_module_id {
 
                                // This new symbol is imported by a foreign
 
                                // module, so this is an error
 
                                debug_assert!(symbol.is_some());
 
                                debug_assert!(symbol.unwrap().is_namespace());
 
                                debug_assert!(iter.num_returned() > 1);
 
                                symbol = None;
 
                                break;
 
                            }
 
                            within_module_id = *new_root_id;
 
                            symbol = Some(new_symbol);
 
                        },
 
                        Symbol::Definition((definition_root_id, _)) => {
 
                            // Found a definition, but if we already jumped
 
                            // modules, then this must be defined within that
 
                            // module.
 
                            if root_module_id != within_module_id && within_module_id != *definition_root_id {
 
                                // This is an imported definition within the module
 
                                // TODO: Maybe factor out? Dunno...
 
                                // So keep the old 
 
                                debug_assert!(symbol.is_some());
 
                                debug_assert!(symbol.unwrap().is_namespace());
 
                                debug_assert!(iter.num_returned() > 1);
 
                                let to_skip = iter.num_returned() - 1;
 
                                iter = identifier.iter();
 
                                for _ in 0..to_skip { iter.next(); }
 
                                symbol = None;
 
                                break;
 
                            }
 
                            symbol = Some(new_symbol);
 
                            break;
 
                        }
 
                    }
 
                }
 
            }
 

	
 
            if poly_args.is_some() {
 
                // Polymorphic argument specification should also be a fully 
 
                // resolved result.
 
                break;
 
            }
 
        }
 

	
 
        match symbol {
 
            None => Ok(None),
 
            Some(symbol) => Ok(Some((symbol, iter)))
 
            None => (None, iter),
 
            Some(symbol) => (Some(symbol), iter)
 
        }
 
    }
 

	
 
    /// Attempts to add a namespace symbol. Returns `Ok` if the symbol was
 
    /// inserted. If the symbol already exists then `Err` will be returned
 
    /// together with the previous definition's source position (in the origin
 
    /// module's source file).
 
    // Note: I would love to return a reference to the value, but Rust is
 
    // preventing me from doing so... That, or I'm not smart enough...
 
    fn add_namespace_symbol(
 
        &mut self, origin_module_id: RootId, origin_position: InputPosition, symbol_name: &Vec<u8>, target_module_id: RootId
 
        &mut self, origin_position: InputPosition, key: SymbolKey, target_module_id: RootId
 
    ) -> Result<(), InputPosition> {
 
        let key = SymbolKey{
 
            module_id: origin_module_id,
 
            symbol_name: symbol_name.clone()
 
        };
 
        match self.symbol_lookup.entry(key) {
 
            Entry::Occupied(o) => Err(o.get().position),
 
            Entry::Vacant(v) => {
 
                v.insert(SymbolValue{
 
                    position: origin_position,
 
                    symbol: Symbol::Namespace(target_module_id)
 
                });
 
                Ok(())
 
            }
 
        }
 
    }
 

	
 
    /// Attempts to add a definition symbol. Returns `Ok` if the symbol was
 
    /// inserted. If the symbol already exists then `Err` will be returned
 
    /// together with the previous definition's source position (in the origin
 
    /// module's source file).
 
    fn add_definition_symbol(
 
        &mut self, origin_module_id: RootId, origin_position: InputPosition, symbol_name: &Vec<u8>,
 
        &mut self, origin_position: InputPosition, key: SymbolKey,
 
        target_module_id: RootId, target_definition_id: DefinitionId,
 
    ) -> Result<(), InputPosition> {
 
        let key = SymbolKey{
 
            module_id: origin_module_id,
 
            symbol_name: symbol_name.clone()
 
        };
 
        match self.symbol_lookup.entry(key) {
 
            Entry::Occupied(o) => Err(o.get().position),
 
            Entry::Vacant(v) => {
 
                v.insert(SymbolValue {
 
                    position: origin_position,
 
                    symbol: Symbol::Definition((target_module_id, target_definition_id))
 
                });
 
                Ok(())
 
            }
 
        }
 
    }
 
}
 
\ No newline at end of file
src/protocol/parser/type_table.rs
Show inline comments
 
@@ -848,103 +848,120 @@ impl TypeTable {
 
                PTV::Inferred => {
 
                    debug_assert!(false, "Encountered illegal ParserTypeVariant within type definition");
 
                    unreachable!();
 
                },
 
                // Symbolic type, make sure its base type, and the base types
 
                // of all members of the embedded type tree are resolved. We
 
                // don't care about monomorphs yet.
 
                PTV::Symbolic(symbolic) => {
 
                    // Check if the symbolic type is one of the definition's
 
                    // polymorphic arguments. If so then we can halt the
 
                    // execution
 
                    for (poly_arg_idx, poly_arg) in poly_vars.iter().enumerate() {
 
                        if *poly_arg == symbolic.identifier {
 
                        if symbolic.identifier == *poly_arg {
 
                            set_resolve_result(ResolveResult::PolyArg(poly_arg_idx));
 
                            continue 'resolve_loop;
 
                        }
 
                    }
 

	
 
                    // Lookup the definition in the symbol table
 
                    let symbol = ctx.symbols.resolve_namespaced_symbol(root_id, &symbolic.identifier);
 
                    let (symbol, mut ident_iter) = ctx.symbols.resolve_namespaced_symbol(root_id, &symbolic.identifier);
 
                    if symbol.is_none() {
 
                        return Err(ParseError2::new_error(
 
                            &ctx.modules[root_id.index as usize].source, symbolic.identifier.position,
 
                            "Could not resolve type"
 
                        ))
 
                    }
 

	
 
                    let (symbol_value, mut ident_iter) = symbol.unwrap();
 
                    let symbol_value = symbol.unwrap();
 
                    let module_source = &ctx.modules[root_id.index as usize].source;
 

	
 
                    match symbol_value.symbol {
 
                        Symbol::Namespace(_) => {
 
                            // Reference to a namespace instead of a type
 
                            let last_ident = ident_iter.prev();
 
                            return if ident_iter.num_remaining() == 0 {
 
                                // Could also have polymorphic args, but we 
 
                                // don't care, just throw this error: 
 
                                Err(ParseError2::new_error(
 
                                    &ctx.modules[root_id.index as usize].source, symbolic.identifier.position,
 
                                    module_source, symbolic.identifier.position,
 
                                    "Expected a type, got a module name"
 
                                ))
 
                            } else {
 
                                let next_identifier = ident_iter.next().unwrap();
 
                            } else if last_ident.is_some() && last_ident.map(|(_, poly_args)| poly_args.is_some()).unwrap() {
 
                                // Halted at a namespaced because we encountered
 
                                // polymorphic arguments
 
                                Err(ParseError2::new_error(
 
                                    &ctx.modules[root_id.index as usize].source, symbolic.identifier.position,
 
                                    &format!("Could not find symbol '{}' with this module", String::from_utf8_lossy(next_identifier))
 
                                    module_source, symbolic.identifier.position,
 
                                    "Illegal specification of polymorphic arguments to a module name"
 
                                ))
 
                            } else {
 
                                // Impossible (with the current implementation 
 
                                // of the symbol table)
 
                                unreachable!(
 
                                    "Got namespace symbol with {} returned symbols from {}",
 
                                    ident_iter.num_returned(),
 
                                    &String::from_utf8_lossy(&symbolic.identifier.value)
 
                                );
 
                            }
 
                        },
 
                        Symbol::Definition((root_id, definition_id)) => {
 
                            let definition = &ctx.heap[definition_id];
 
                            if ident_iter.num_remaining() > 0 {
 
                                // Namespaced identifier is longer than the type
 
                                // we found. Return the appropriate message
 
                                return if definition.is_struct() || definition.is_enum() {
 
                                    Err(ParseError2::new_error(
 
                                        &ctx.modules[root_id.index as usize].source, symbolic.identifier.position,
 
                                        module_source, symbolic.identifier.position,
 
                                        &format!(
 
                                            "Unknown type '{}', did you mean to use '{}'?",
 
                                            String::from_utf8_lossy(&symbolic.identifier.value),
 
                                            String::from_utf8_lossy(&definition.identifier().value)
 
                                        )
 
                                    ))
 
                                } else {
 
                                    Err(ParseError2::new_error(
 
                                        &ctx.modules[root_id.index as usize].source, symbolic.identifier.position,
 
                                        "Unknown type"
 
                                        module_source, symbolic.identifier.position,
 
                                        "Unknown datatype"
 
                                    ))
 
                                }
 
                            }
 

	
 
                            // Found a match, make sure it is a datatype
 
                            if !(definition.is_struct() || definition.is_enum()) {
 
                                return Err(ParseError2::new_error(
 
                                    &ctx.modules[root_id.index as usize].source, symbolic.identifier.position,
 
                                    module_source, symbolic.identifier.position,
 
                                    "Embedded types must be datatypes (structs or enums)"
 
                                ))
 
                            }
 

	
 
                            // Found a struct/enum definition
 
                            if !self.lookup.contains_key(&definition_id) {
 
                                // Type is not yet resoled, immediately return
 
                                // this
 
                                return Ok(ResolveResult::Unresolved((root_id, definition_id)));
 
                            }
 

	
 
                            // Type is resolved, so set as result, but continue
 
                            // iterating over the parser types in the embedded
 
                            // type's tree
 
                            set_resolve_result(ResolveResult::Resolved((root_id, definition_id)));
 

	
 
                            // Note: because we're resolving parser types, not
 
                            // embedded types, we're parsing a tree, so we can't
 
                            // get stuck in a cyclic loop.
 
                            for poly_arg_type_id in &symbolic.poly_args {
 
                                self.parser_type_iter.push_back(*poly_arg_type_id);
 
                            let last_ident = ident_iter.prev();
 
                            if let Some((_, Some(poly_args))) = last_ident {
 
                                for poly_arg_type_id in poly_args {
 
                                    self.parser_type_iter.push_back(*poly_arg_type_id);
 
                                }
 
                            }
 
                        }
 
                    }
 
                }
 
            }
 
        }
 

	
 
        // If here then all types in the embedded type's tree were resolved.
 
        debug_assert!(resolve_result.is_some(), "faulty logic in ParserType resolver");
 
        return Ok(resolve_result.unwrap())
 
    }
 

	
 
@@ -992,51 +1009,62 @@ impl TypeTable {
 
                    //  the parser/lexer
 
                    // debug_assert!(false, "encountered illegal parser type during ParserType/PolyArg modification");
 
                    // unreachable!();
 
                },
 
                PTV::Array(subtype_id) |
 
                PTV::Input(subtype_id) |
 
                PTV::Output(subtype_id) => {
 
                    // Outer type is fixed, but inner type might be symbolix
 
                    self.parser_type_iter.push_back(*subtype_id);
 
                },
 
                PTV::Symbolic(symbolic) => {
 
                    for (poly_arg_idx, poly_arg) in poly_args.iter_mut().enumerate() {
 
                        if poly_arg.identifier == symbolic.identifier {
 
                        if symbolic.identifier == poly_arg.identifier {
 
                            poly_arg.is_in_use = true;
 
                            // TODO: If we allow higher-kinded types in the future,
 
                            //  then we can't continue here, but must resolve the
 
                            //  polyargs as well
 
                            debug_assert!(symbolic.poly_args.is_empty(), "got polymorphic arguments to a polymorphic variable");
 
                            debug_assert!(!symbolic.identifier.has_poly_args(), "got polymorphic arguments to a polymorphic variable");
 
                            debug_assert!(symbolic.variant.is_none(), "symbolic parser type's variant already resolved");
 
                            symbolic.variant = Some(SymbolicParserTypeVariant::PolyArg(type_definition_id, poly_arg_idx));
 
                            continue 'type_loop;
 
                        }
 
                    }
 

	
 
                    // Must match a definition
 
                    let symbol = ctx.symbols.resolve_namespaced_symbol(root_id, &symbolic.identifier);
 
                    let (symbol, _) = ctx.symbols.resolve_namespaced_symbol(root_id, &symbolic.identifier);
 
                    debug_assert!(symbol.is_some(), "could not resolve symbolic parser type when determining poly args");
 
                    let (symbol, ident_iter) = symbol.unwrap();
 
                    debug_assert_eq!(ident_iter.num_remaining(), 0, "no exact symbol match when determining poly args");
 
                    let (_root_id, definition_id) = symbol.as_definition().unwrap();
 
    
 
                    // Must be a struct, enum, or union
 
                    // Must be a struct, enum, or union, we checked this
 
                    let defined_type = self.lookup.get(&definition_id).unwrap();
 
                    if cfg!(debug_assertions) {
 
                        // Make sure type class is correct
 
                        let type_class = defined_type.definition.type_class();
 
                        debug_assert!(
 
                            type_class == TypeClass::Struct || type_class == TypeClass::Enum || type_class == TypeClass::Union,
 
                            "embedded type's class is not struct, enum or union"
 
                        );
 
                        // Make sure polymorphic arguments occurred at the end
 
                        let num_poly = symbolic.identifier.iter()
 
                            .map(|(_, v)| v)
 
                            .filter(|v| v.is_some())
 
                            .count();
 
                        debug_assert!(num_poly <= 1, "more than one section with polymorphic arguments");
 
                        if num_poly == 1 {
 
                            let (_, poly_args) = symbolic.identifier.iter().last().unwrap();
 
                            debug_assert!(poly_args.is_some(), "got poly args, but not at end of identifier");
 
                        }
 
                    }
 
    
 
                    if symbolic.poly_args.len() != defined_type.poly_args.len() {
 
                        // Mismatch in number of polymorphic arguments. This is 
 
                        // not allowed in type definitions (no inference is 
 
                        // allowed within type definitions, only in bodies of
 
                        // functions/components).
 
                        let module_source = &ctx.modules[root_id.index as usize].source;
 
                        let number_args_msg = if defined_type.poly_args.is_empty() {
 
                            String::from("is not polymorphic")
 
                        } else {
 
                            format!("accepts {} polymorphic arguments", defined_type.poly_args.len())
src/protocol/tests/parser_imports.rs
Show inline comments
 
@@ -136,13 +136,18 @@ fn test_multi_symbol_import() {
 
    //     struct Bar { byte b };
 
    //     ")
 
    //     .with_source("
 
    //     import external::*;
 
    //     byte caller() {
 
    //         auto f = Foo{f:0};
 
    //         auto b = Bar{b:0};
 
    //         return f.f + b.b;
 
    //     }
 
    //     ")
 
    //     .compile()
 
    //     .expect_ok();
 
}
 
\ No newline at end of file
 
}
 

	
 
// TODO: Test incorrect imports:
 
//  1. importing a module
 
//  2. import something a module imports
 
//  3. import something that doesn't exist in a module
 
\ No newline at end of file
0 comments (0 inline, 0 general)