diff --git a/src/protocol/parser/mod.rs b/src/protocol/parser/mod.rs index 90e97a8ae61e65ce0e5ac6aacca14348c8b3bc62..c2c572555bbb71d197030a636a359dc4f7912b72 100644 --- a/src/protocol/parser/mod.rs +++ b/src/protocol/parser/mod.rs @@ -1,7 +1,6 @@ mod depth_visitor; -mod symbol_table; -// mod type_table_old; -mod type_table; +pub(crate) mod symbol_table; +pub(crate) mod type_table; mod type_resolver; mod visitor; mod visitor_linker; @@ -26,13 +25,15 @@ pub(crate) struct LexedModule { pub(crate) source: InputSource, module_name: Vec, version: Option, - root_id: RootId, + pub(crate) root_id: RootId, } pub struct Parser { pub(crate) heap: Heap, pub(crate) modules: Vec, pub(crate) module_lookup: HashMap, usize>, // from (optional) module name to `modules` idx + pub(crate) symbol_table: SymbolTable, + pub(crate) type_table: TypeTable, } impl Parser { @@ -40,17 +41,12 @@ impl Parser { Parser{ heap: Heap::new(), modules: Vec::new(), - module_lookup: HashMap::new() + module_lookup: HashMap::new(), + symbol_table: SymbolTable::new(), + type_table: TypeTable::new(), } } - // TODO: @fix, temporary implementation to keep code compilable - pub fn new_with_source(source: InputSource) -> Result { - let mut parser = Parser::new(); - parser.feed(source)?; - Ok(parser) - } - pub fn feed(&mut self, mut source: InputSource) -> Result { // Lex the input source let mut lex = Lexer::new(&mut source); @@ -127,23 +123,16 @@ impl Parser { Ok(pd) } - pub fn compile(&mut self) { - // Build module lookup - } - - fn resolve_symbols_and_types(&mut self) -> Result<(SymbolTable, TypeTable), ParseError2> { + fn resolve_symbols_and_types(&mut self) -> Result<(), ParseError2> { // 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. - // TODO: Update once namespaced identifiers are implemented - let symbol_table = SymbolTable::new(&self.heap, &self.modules)?; + 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. - // TODO: Maybe directly access heap's members to allow borrowing from - // mutliple members of Heap? Not pretty though... let mut module_index = 0; let mut import_index = 0; loop { @@ -166,19 +155,19 @@ impl Parser { match import { Import::Module(import) => { debug_assert!(import.module_id.is_none(), "module import already resolved"); - let target_module_id = symbol_table.resolve_module(&import.module_name) + let target_module_id = self.symbol_table.resolve_module(&import.module_name) .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 = symbol_table.resolve_module(&import.module_name) + let target_module_id = self.symbol_table.resolve_module(&import.module_name) .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) = symbol_table.resolve_symbol(module_root_id, &symbol.alias) + let (_, target_definition_id) = self.symbol_table.resolve_symbol(module_root_id, &symbol.alias) .expect("symbol import is resolved by symbol table") .as_definition() .expect("symbol import does not resolve to namespace symbol"); @@ -190,46 +179,64 @@ impl Parser { // 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(&symbol_table, &mut self.heap, &self.modules); - let type_table = TypeTable::new(&mut type_ctx)?; + let mut type_ctx = TypeCtx::new(&self.symbol_table, &mut self.heap, &self.modules); + self.type_table.build_base_types(&mut type_ctx)?; - Ok((symbol_table, type_table)) + Ok(()) } - // TODO: @fix, temporary impl to keep code compilable - pub fn parse(&mut self) -> Result { - assert_eq!(self.modules.len(), 1, "Fix meeeee"); - let root_id = self.modules[0].root_id; - - let (mut symbol_table, mut type_table) = self.resolve_symbols_and_types()?; + pub fn parse(&mut self) -> Result<(), ParseError2> { + self.resolve_symbols_and_types()?; - // TODO: @cleanup - let mut ctx = visitor::Ctx{ - heap: &mut self.heap, - module: &self.modules[0], - symbols: &mut symbol_table, - types: &mut type_table, - }; + // Validate and link all modules let mut visit = ValidityAndLinkerVisitor::new(); - visit.visit_module(&mut ctx)?; - let mut type_visit = TypeResolvingVisitor::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(); - TypeResolvingVisitor::queue_module_definitions(&ctx, &mut queue); + 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(); - println!("Resolving root={}, def={}, mono={:?}", top.root_id.index, top.definition_id.index, top.monomorph_types); - type_visit.handle_module_definition(&mut ctx, &mut queue, top)?; + 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)?; } - if let Err((position, message)) = Self::parse_inner(&mut self.heap, root_id) { - return Err(ParseError2::new_error(&self.modules[0].source, position, &message)) + // 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(ParseError2::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(root_id) + Ok(()) } pub fn parse_inner(h: &mut Heap, pd: RootId) -> VisitorResult { @@ -252,143 +259,4 @@ impl Parser { Ok(()) } -} - -#[cfg(test)] -mod tests { - use std::fs::File; - use std::io::Read; - use std::path::Path; - - use super::*; - - // #[test] - fn positive_tests() { - for resource in TestFileIter::new("testdata/parser/positive", "pdl") { - let resource = resource.expect("read testdata filepath"); - // println!(" * running: {}", &resource); - let path = Path::new(&resource); - let source = InputSource::from_file(&path).unwrap(); - // println!("DEBUG -- input:\n{}", String::from_utf8_lossy(&source.input)); - let mut parser = Parser::new_with_source(source).expect("parse source"); - match parser.parse() { - Ok(_) => {} - Err(err) => { - println!(" > file: {}", &resource); - println!("{}", err); - assert!(false); - } - } - } - } - - // #[test] - fn negative_tests() { - for resource in TestFileIter::new("testdata/parser/negative", "pdl") { - let resource = resource.expect("read testdata filepath"); - let path = Path::new(&resource); - let expect = path.with_extension("txt"); - let mut source = InputSource::from_file(&path).unwrap(); - let mut parser = Parser::new_with_source(source).expect("construct parser"); - match parser.parse() { - Ok(pd) => { - println!("Expected parse error:"); - - let mut cev: Vec = Vec::new(); - let mut f = File::open(expect).unwrap(); - f.read_to_end(&mut cev).unwrap(); - println!("{}", String::from_utf8_lossy(&cev)); - assert!(false); - } - Err(err) => { - let expected = format!("{}", err); - println!("{}", &expected); - - let mut cev: Vec = Vec::new(); - let mut f = File::open(expect).unwrap(); - f.read_to_end(&mut cev).unwrap(); - println!("{}", String::from_utf8_lossy(&cev)); - - assert_eq!(expected.as_bytes(), cev); - } - } - } - } - - // #[test] - fn counterexample_tests() { - for resource in TestFileIter::new("testdata/parser/counterexamples", "pdl") { - let resource = resource.expect("read testdata filepath"); - let path = Path::new(&resource); - let source = InputSource::from_file(&path).unwrap(); - let mut parser = Parser::new_with_source(source).expect("construct parser"); - - fn print_header(s: &str) { - println!("{}", "=".repeat(80)); - println!(" > File: {}", s); - println!("{}", "=".repeat(80)); - } - - match parser.parse() { - Ok(parsed) => { - print_header(&resource); - println!("\n SUCCESS\n\n --- source:\n{}", String::from_utf8_lossy(&parser.modules[0].source.input)); - }, - Err(err) => { - print_header(&resource); - println!( - "\n FAILURE\n\n --- error:\n{}\n --- source:\n{}", - err, - String::from_utf8_lossy(&parser.modules[0].source.input) - ) - } - } - } - } - - struct TestFileIter { - iter: std::fs::ReadDir, - root: String, - extension: String - } - - impl TestFileIter { - fn new(root_dir: &str, extension: &str) -> Self { - let path = Path::new(root_dir); - assert!(path.is_dir(), "root '{}' is not a directory", root_dir); - - let iter = std::fs::read_dir(path).expect("list dir contents"); - - Self { - iter, - root: root_dir.to_string(), - extension: extension.to_string(), - } - } - } - - impl Iterator for TestFileIter { - type Item = Result; - - fn next(&mut self) -> Option { - while let Some(entry) = self.iter.next() { - if let Err(e) = entry { - return Some(Err(format!("failed to read dir entry, because: {}", e))); - } - let entry = entry.unwrap(); - - let path = entry.path(); - if !path.is_file() { continue; } - - let extension = path.extension(); - if extension.is_none() { continue; } - let extension = extension.unwrap().to_string_lossy(); - if extension != self.extension { continue; } - - return Some(Ok(path.to_string_lossy().to_string())); - } - - None - } - } -} +} \ No newline at end of file