Files @ fcf8c30ed335
Branch filter:

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

fcf8c30ed335 11.7 KiB application/rls-services+xml Show Source Show as Raw Download as Raw
mh
WIP on fixing type inferencer
33ea10021de4
9774ef9fe888
7f25ee16c39b
9774ef9fe888
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
f091e98ceccd
b194b811d0cc
6af17d60c197
cd546710a6c9
33ea10021de4
33ea10021de4
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
a23c6c8e99e9
6af17d60c197
6ec2e0261a03
fdaf709bf0ca
33ea10021de4
06f259bf8031
ddddcd3cc9aa
06f259bf8031
06f259bf8031
33ea10021de4
729feec4d37a
06f259bf8031
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
17fe648a8934
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
ddddcd3cc9aa
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
9774ef9fe888
06f259bf8031
06f259bf8031
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
9774ef9fe888
9774ef9fe888
06f259bf8031
06f259bf8031
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
9774ef9fe888
9774ef9fe888
9774ef9fe888
b826e300c566
06f259bf8031
06f259bf8031
c87205ed6292
33ea10021de4
33ea10021de4
33ea10021de4
06f259bf8031
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
06f259bf8031
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
c87205ed6292
33ea10021de4
33ea10021de4
33ea10021de4
06f259bf8031
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
c87205ed6292
33ea10021de4
33ea10021de4
33ea10021de4
06f259bf8031
33ea10021de4
33ea10021de4
33ea10021de4
06f259bf8031
06f259bf8031
06f259bf8031
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
06f259bf8031
33ea10021de4
33ea10021de4
06f259bf8031
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
c87205ed6292
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
06f259bf8031
06f259bf8031
c87205ed6292
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
9774ef9fe888
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
06f259bf8031
06f259bf8031
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
06f259bf8031
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
ddddcd3cc9aa
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
ddddcd3cc9aa
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
28df9835906f
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
33ea10021de4
06f259bf8031
06f259bf8031
e406c61b1158
e406c61b1158
06f259bf8031
06f259bf8031
33ea10021de4
33ea10021de4
9774ef9fe888
9774ef9fe888
b194b811d0cc
9774ef9fe888
06f259bf8031
06f259bf8031
c87205ed6292
9774ef9fe888
6717437470eb
9774ef9fe888
6af17d60c197
9774ef9fe888
9774ef9fe888
9774ef9fe888
9774ef9fe888
9774ef9fe888
9774ef9fe888
9774ef9fe888
9774ef9fe888
9774ef9fe888
9774ef9fe888
9774ef9fe888
9774ef9fe888
6ec2e0261a03
9774ef9fe888
9774ef9fe888
9774ef9fe888
9774ef9fe888
9774ef9fe888
9774ef9fe888
9774ef9fe888
9774ef9fe888
9774ef9fe888
6ec2e0261a03
6ec2e0261a03
9774ef9fe888
9774ef9fe888
9774ef9fe888
9774ef9fe888
9774ef9fe888
9774ef9fe888
9774ef9fe888
6ec2e0261a03
729feec4d37a
9774ef9fe888
9774ef9fe888
9774ef9fe888
9774ef9fe888
9774ef9fe888
c87205ed6292
9774ef9fe888
06f259bf8031
6717437470eb
3c33e2928fb4
3c33e2928fb4
3c33e2928fb4
ca97483c6ec7
9774ef9fe888
06f259bf8031
06f259bf8031
33ea10021de4
6717437470eb
729feec4d37a
729feec4d37a
729feec4d37a
729feec4d37a
729feec4d37a
729feec4d37a
ca97483c6ec7
729feec4d37a
729feec4d37a
06f259bf8031
6717437470eb
6717437470eb
06f259bf8031
06f259bf8031
06f259bf8031
33ea10021de4
33ea10021de4
06f259bf8031
9774ef9fe888
mod depth_visitor;
pub(crate) mod symbol_table;
pub(crate) mod symbol_table2;
pub(crate) mod type_table;
pub(crate) mod tokens;
pub(crate) mod token_parsing;
pub(crate) mod pass_tokenizer;
pub(crate) mod pass_symbols;
pub(crate) mod pass_imports;
pub(crate) mod pass_definitions;
mod type_resolver;
mod visitor;
mod pass_validation_linking;
mod utils;

use depth_visitor::*;
use tokens::*;
use crate::collections::*;
use symbol_table2::SymbolTable;
use visitor::Visitor2;
use pass_validation_linking::PassValidationLinking;
use type_resolver::{TypeResolvingVisitor, ResolveQueue};
use type_table::{TypeTable, TypeCtx};

use crate::protocol::ast::*;
use crate::protocol::input_source2::{InputSource2 as InputSource};
use crate::protocol::lexer::*;

use std::collections::HashMap;
use crate::protocol::ast_printer::ASTWriter;

#[derive(PartialEq, Eq)]
pub enum ModuleCompilationPhase {
    Source,                 // only source is set
    Tokenized,              // source is tokenized
    SymbolsScanned,         // all definitions are linked to their type class
    ImportsResolved,        // all imports are added to the symbol table
    DefinitionsParsed,      // produced the AST for the entire module
    TypesParsed,            // added all definitions to the type table
    ValidatedAndLinked,     // AST is traversed and has linked the required AST nodes
    Typed,                  // Type inference and checking has been performed
}

pub struct Module {
    // Buffers
    source: InputSource,
    tokens: TokenBuffer,
    // Identifiers
    root_id: RootId,
    name: Option<(PragmaId, StringRef<'static>)>,
    version: Option<(PragmaId, i64)>,
    phase: ModuleCompilationPhase,
}

pub struct PassCtx<'a> {
    heap: &'a mut Heap,
    symbols: &'a mut SymbolTable,
    pool: &'a mut StringPool,
}

// TODO: @fixme, pub qualifier
pub(crate) struct LexedModule {
    pub(crate) source: InputSource,
    module_name: Vec<u8>,
    version: Option<u64>,
    pub(crate) root_id: RootId,
}

pub struct Parser {
    pub(crate) heap: Heap,
    pub(crate) modules: Vec<LexedModule>,
    pub(crate) module_lookup: HashMap<Vec<u8>, usize>, // from (optional) module name to `modules` idx
    pub(crate) symbol_table: SymbolTable,
    pub(crate) type_table: TypeTable,
}

impl Parser {
    pub fn new() -> Self {
        Parser{
            heap: Heap::new(),
            modules: Vec::new(),
            module_lookup: HashMap::new(),
            symbol_table: SymbolTable::new(),
            type_table: TypeTable::new(),
        }
    }

    pub fn feed(&mut self, mut source: InputSource) -> Result<RootId, ParseError> {
        // Lex the input source
        let mut lex = Lexer::new(&mut source);
        let pd = lex.consume_protocol_description(&mut self.heap)?;

        // Seek the module name and version
        let root = &self.heap[pd];
        let mut module_name_pos = InputPosition::default();
        let mut module_name = Vec::new();
        let mut module_version_pos = InputPosition::default();
        let mut module_version = None;

        for pragma in &root.pragmas {
            match &self.heap[*pragma] {
                Pragma::Module(module) => {
                    if !module_name.is_empty() {
                        return Err(
                            ParseError::new_error(&source, module.position, "Double definition of module name in the same file")
                                .with_postfixed_info(&source, module_name_pos, "Previous definition was here")
                        )
                    }

                    module_name_pos = module.position.clone();
                    module_name = module.value.clone();
                },
                Pragma::Version(version) => {
                    if module_version.is_some() {
                        return Err(
                            ParseError::new_error(&source, version.position, "Double definition of module version")
                                .with_postfixed_info(&source, module_version_pos, "Previous definition was here")
                        )
                    }

                    module_version_pos = version.position.clone();
                    module_version = Some(version.version);
                },
            }
        }

        // Add module to list of modules and prevent naming conflicts
        let cur_module_idx = self.modules.len();
        if let Some(prev_module_idx) = self.module_lookup.get(&module_name) {
            // Find `#module` statement in other module again
            let prev_module = &self.modules[*prev_module_idx];
            let prev_module_pos = self.heap[prev_module.root_id].pragmas
                .iter()
                .find_map(|p| {
                    match &self.heap[*p] {
                        Pragma::Module(module) => Some(module.position.clone()),
                        _ => None
                    }
                })
                .unwrap_or(InputPosition::default());

            let module_name_msg = if module_name.is_empty() {
                format!("a nameless module")
            } else {
                format!("module '{}'", String::from_utf8_lossy(&module_name))
            };

            return Err(
                ParseError::new_error(&source, module_name_pos, &format!("Double definition of {} across files", module_name_msg))
                    .with_postfixed_info(&prev_module.source, prev_module_pos, "Other definition was here")
            );
        }

        self.modules.push(LexedModule{
            source,
            module_name: module_name.clone(),
            version: module_version,
            root_id: pd
        });
        self.module_lookup.insert(module_name, cur_module_idx);
        Ok(pd)
    }

    fn resolve_symbols_and_types(&mut self) -> Result<(), ParseError> {
        // Construct the symbol table to resolve any imports and/or definitions,
        // then use the symbol table to actually annotate all of the imports.
        // If the type table is constructed correctly then all imports MUST be
        // resolvable.
        self.symbol_table.build(&self.heap, &self.modules)?;

        // Not pretty, but we need to work around rust's borrowing rules, it is
        // totally safe to mutate the contents of an AST element that we are
        // not borrowing anywhere else.
        let mut module_index = 0;
        let mut import_index = 0;
        loop {
            if module_index >= self.modules.len() {
                break;
            }

            let module_root_id = self.modules[module_index].root_id;
            let import_id = {
                let root = &self.heap[module_root_id];
                if import_index >= root.imports.len() {
                    module_index += 1;
                    import_index = 0;
                    continue
                }
                root.imports[import_index]
            };

            let import = &mut self.heap[import_id];
            match import {
                Import::Module(import) => {
                    debug_assert!(import.module_id.is_none(), "module import already resolved");
                    let target_module_id = self.symbol_table.resolve_module(&import.module)
                        .expect("module import is resolved by symbol table");
                    import.module_id = Some(target_module_id)
                },
                Import::Symbols(import) => {
                    debug_assert!(import.module_id.is_none(), "module of symbol import already resolved");
                    let target_module_id = self.symbol_table.resolve_module(&import.module)
                        .expect("symbol import's module is resolved by symbol table");
                    import.module_id = Some(target_module_id);

                    for symbol in &mut import.symbols {
                        debug_assert!(symbol.definition_id.is_none(), "symbol import already resolved");
                        let (_, target_definition_id) = self.symbol_table.resolve_identifier(module_root_id, &symbol.alias)
                            .expect("symbol import is resolved by symbol table")
                            .as_definition()
                            .expect("symbol import does not resolve to namespace symbol");
                        symbol.definition_id = Some(target_definition_id);
                    }
                }
            }

            import_index += 1;
        }

        // All imports in the AST are now annotated. We now use the symbol table
        // to construct the type table.
        let mut type_ctx = TypeCtx::new(&self.symbol_table, &mut self.heap, &self.modules);
        self.type_table.build_base_types(&mut type_ctx)?;

        Ok(())
    }

    pub fn parse(&mut self) -> Result<(), ParseError> {
        self.resolve_symbols_and_types()?;

        // Validate and link all modules
        let mut visit = PassValidationLinking::new();
        for module in &self.modules {
            let mut ctx = visitor::Ctx{
                heap: &mut self.heap,
                module,
                symbols: &mut self.symbol_table,
                types: &mut self.type_table,
            };
            visit.visit_module(&mut ctx)?;
        }

        // Perform typechecking on all modules
        let mut visit = TypeResolvingVisitor::new();
        let mut queue = ResolveQueue::new();
        for module in &self.modules {
            let ctx = visitor::Ctx{
                heap: &mut self.heap,
                module,
                symbols: &mut self.symbol_table,
                types: &mut self.type_table,
            };
            TypeResolvingVisitor::queue_module_definitions(&ctx, &mut queue);   
        };
        while !queue.is_empty() {
            let top = queue.pop().unwrap();
            let mut ctx = visitor::Ctx{
                heap: &mut self.heap,
                module: &self.modules[top.root_id.index as usize],
                symbols: &mut self.symbol_table,
                types: &mut self.type_table,
            };
            visit.handle_module_definition(&mut ctx, &mut queue, top)?;
        }

        // Perform remaining steps
        // TODO: Phase out at some point
        for module in &self.modules {
            let root_id = module.root_id;
            if let Err((position, message)) = Self::parse_inner(&mut self.heap, root_id) {
                return Err(ParseError::new_error(&self.modules[0].source, position, &message))
            }
        }

        // let mut writer = ASTWriter::new();
        // let mut file = std::fs::File::create(std::path::Path::new("ast.txt")).unwrap();
        // writer.write_ast(&mut file, &self.heap);

        Ok(())
    }

    pub fn parse_inner(h: &mut Heap, pd: RootId) -> VisitorResult {
        // TODO: @cleanup, slowly phasing out old compiler
        // NestedSynchronousStatements::new().visit_protocol_description(h, pd)?;
        // ChannelStatementOccurrences::new().visit_protocol_description(h, pd)?;
        // FunctionStatementReturns::new().visit_protocol_description(h, pd)?;
        // ComponentStatementReturnNew::new().visit_protocol_description(h, pd)?;
        // CheckBuiltinOccurrences::new().visit_protocol_description(h, pd)?;
        // BuildSymbolDeclarations::new().visit_protocol_description(h, pd)?;
        // LinkCallExpressions::new().visit_protocol_description(h, pd)?;
        // BuildScope::new().visit_protocol_description(h, pd)?;
        // ResolveVariables::new().visit_protocol_description(h, pd)?;
        LinkStatements::new().visit_protocol_description(h, pd)?;
        // BuildLabels::new().visit_protocol_description(h, pd)?;
        // ResolveLabels::new().visit_protocol_description(h, pd)?;
        AssignableExpressions::new().visit_protocol_description(h, pd)?;
        IndexableExpressions::new().visit_protocol_description(h, pd)?;
        SelectableExpressions::new().visit_protocol_description(h, pd)?;

        Ok(())
    }
}