From e1432caf073547ef04df39143614a6525354bea6 2022-03-25 10:37:47 From: MH Date: 2022-03-25 10:37:47 Subject: [PATCH] Replace reserved keywords with global std lib funcs --- diff --git a/src/protocol/ast_printer.rs b/src/protocol/ast_writer.rs similarity index 100% rename from src/protocol/ast_printer.rs rename to src/protocol/ast_writer.rs diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index b60caaf6e913262eeb6de01dc0cdc5f74a85aac7..f2b4fd7cdd1de22103ea9a251f737a130107d5ee 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -5,7 +5,7 @@ mod parser; #[cfg(test)] mod tests; pub(crate) mod ast; -pub(crate) mod ast_printer; +pub(crate) mod ast_writer; use std::sync::Mutex; diff --git a/src/protocol/parser/mod.rs b/src/protocol/parser/mod.rs index 50f002e4de01949cb9db20e76a9ee5d088d49688..79f4c0fed6768f538799073c591e410813060cff 100644 --- a/src/protocol/parser/mod.rs +++ b/src/protocol/parser/mod.rs @@ -30,7 +30,7 @@ use type_table::*; use crate::protocol::ast::*; use crate::protocol::input_source::*; -use crate::protocol::ast_printer::ASTWriter; +use crate::protocol::ast_writer::ASTWriter; use crate::protocol::parser::type_table::PolymorphicVariable; const REOWOLF_PATH_ENV: &'static str = "REOWOLF_ROOT"; // first lookup reowolf path @@ -121,6 +121,7 @@ pub struct Parser { pub(crate) modules: Vec, pub(crate) symbol_table: SymbolTable, pub(crate) type_table: TypeTable, + pub(crate) global_module_index: usize, // contains globals, implicitly imported everywhere // Compiler passes, used as little state machine that keep their memory // around. pass_tokenizer: PassTokenizer, @@ -144,6 +145,7 @@ impl Parser { modules: Vec::new(), symbol_table: SymbolTable::new(), type_table: TypeTable::new(), + global_module_index: 0, pass_tokenizer: PassTokenizer::new(), pass_symbols: PassSymbols::new(), pass_import: PassImport::new(), @@ -179,12 +181,16 @@ impl Parser { parser.arch.output_type_id = insert_builtin_type(&mut parser.type_table, vec![ConcreteTypePart::Output, ConcreteTypePart::Void], true, 8, 8); parser.arch.pointer_type_id = insert_builtin_type(&mut parser.type_table, vec![ConcreteTypePart::Pointer, ConcreteTypePart::Void], true, 8, 8); + // Parse standard library parser.feed_standard_library()?; return Ok(parser) } - pub fn feed(&mut self, mut source: InputSource) -> Result<(), ParseError> { + /// Feeds a new InputSource to the parser, which will tokenize it and store + /// it internally for later parsing (when all modules are present). Returns + /// the index of the new module. + pub fn feed(&mut self, mut source: InputSource) -> Result { let mut token_buffer = TokenBuffer::new(); self.pass_tokenizer.tokenize(&mut source, &mut token_buffer)?; @@ -196,9 +202,10 @@ impl Parser { version: None, phase: ModuleCompilationPhase::Tokenized, }; + let module_index = self.modules.len(); self.modules.push(module); - Ok(()) + return Ok(module_index); } pub fn parse(&mut self) -> Result<(), ParseError> { @@ -320,6 +327,8 @@ impl Parser { // way to do this in the future (i.e. a "std" package, containing all // of the modules) let mut file_path = PathBuf::new(); + let mut first_file = true; + for file in FILES { file_path.push(path); file_path.push(file); @@ -335,12 +344,19 @@ impl Parser { let source = source.unwrap(); let input_source = InputSource::new(file.to_string(), source); - if let Err(err) = self.feed(input_source) { + let module_index = self.feed(input_source); + if let Err(err) = module_index { // A bit of a hack, but shouldn't really happen anyway: the // compiler should ship with a decent standard library (at some // point) return Err(format!("{}", err)); } + let module_index = module_index.unwrap(); + + if first_file { + self.global_module_index = module_index; + first_file = false; + } } return Ok(()) diff --git a/src/protocol/parser/pass_definitions.rs b/src/protocol/parser/pass_definitions.rs index e9f1d96120d8954e41f43ac58d3050c0efdc57e8..024c1ea3a753a01b85fb332105ee12d4fb7527f6 100644 --- a/src/protocol/parser/pass_definitions.rs +++ b/src/protocol/parser/pass_definitions.rs @@ -255,6 +255,7 @@ impl PassDefinitions { // Retrieve function name consume_exact_ident(&module.source, iter, KW_FUNCTION)?; let (ident_text, _) = consume_ident(&module.source, iter)?; + let stringy = String::from_utf8_lossy(ident_text).to_string(); // Retrieve preallocated DefinitionId let module_scope = SymbolScope::Module(module.root_id); @@ -342,7 +343,9 @@ impl PassDefinitions { fn consume_procedure_body( &mut self, module: &Module, iter: &mut TokenIter, ctx: &mut PassCtx, definition_id: DefinitionId, kind: ProcedureKind ) -> Result<(BlockStatementId, ProcedureSource), ParseError> { - if iter.peek() == Some(TokenKind::Pragma) { + if iter.next() == Some(TokenKind::OpenCurly) && iter.peek() == Some(TokenKind::Pragma) { + // Consume the placeholder "{ #builtin }" tokens + iter.consume(); // opening curly brace let (pragma, pragma_start, pragma_end) = consume_pragma(&module.source, iter)?; if pragma != b"#builtin" { return Err(ParseError::new_error_str_at_span( @@ -351,6 +354,12 @@ impl PassDefinitions { )); } + if iter.next() != Some(TokenKind::CloseCurly) { + // Just to keep the compiler writers in line ;) + panic!("compiler error: when using the #builtin pragma, wrap it in curly braces"); + } + iter.consume(); + // Retrieve module and procedure name assert!(module.name.is_some(), "compiler error: builtin procedure body in unnamed module"); let (_, module_name) = module.name.as_ref().unwrap(); diff --git a/src/protocol/parser/pass_symbols.rs b/src/protocol/parser/pass_symbols.rs index 995dfa15100c3f0d1e3f44779257ea150cbeb60e..f4bbe5365700fae21e6adb76ebfaea3831f22c87 100644 --- a/src/protocol/parser/pass_symbols.rs +++ b/src/protocol/parser/pass_symbols.rs @@ -195,6 +195,7 @@ impl PassSymbols { // Retrieve identifier of definition let identifier = consume_ident_interned(&module.source, &mut iter, ctx)?; + println!("DEBUG: Parsing {} --- {}", String::from_utf8_lossy(kw_text).to_string(), identifier.value.as_str()); let mut poly_vars = Vec::new(); maybe_consume_comma_separated( TokenKind::OpenAngle, TokenKind::CloseAngle, &module.source, &mut iter, ctx, diff --git a/src/protocol/parser/token_parsing.rs b/src/protocol/parser/token_parsing.rs index 47f02e7f6c2367f467a348b4363af2e28a590014..1a81840b3c5a4c112d01c7cd0e032cc66ba87ecd 100644 --- a/src/protocol/parser/token_parsing.rs +++ b/src/protocol/parser/token_parsing.rs @@ -540,7 +540,8 @@ fn is_reserved_expression_keyword(text: &[u8]) -> bool { match text { KW_LET | KW_CAST | KW_LIT_TRUE | KW_LIT_FALSE | KW_LIT_NULL | - KW_FUNC_GET | KW_FUNC_PUT | KW_FUNC_FIRES | KW_FUNC_CREATE | KW_FUNC_ASSERT | KW_FUNC_LENGTH | KW_FUNC_PRINT => true, + // TODO: Remove this once global namespace errors work @nocommit + // KW_FUNC_GET | KW_FUNC_PUT | KW_FUNC_FIRES | KW_FUNC_CREATE | KW_FUNC_ASSERT | KW_FUNC_LENGTH | KW_FUNC_PRINT => true, _ => false, } } @@ -603,15 +604,16 @@ pub(crate) fn construct_symbol_conflict_error( format!("the type '{}' imported here", symbol.name.as_str()), Some(import.as_symbols().span) ); - } else { - // This is a defined symbol. So this must mean that the - // error was caused by it being defined. - debug_assert_eq!(definition.defined_in_module, module.root_id); - + } else if definition.defined_in_module == module.root_id { + // This is a symbol defined in the same module return ( format!("the type '{}' defined here", symbol.name.as_str()), Some(definition.identifier_span) ) + } else { + // Not imported, not defined in the module, so must be + // a global + return (format!("the global '{}'", symbol.name.as_str()), None) } } } diff --git a/std/std.global.pdl b/std/std.global.pdl index f1cc7bfa898a5991b090afa445c9fb348ce9ebe5..0c67ffe202972f05a301752a1659bdcf367ef0d4 100644 --- a/std/std.global.pdl +++ b/std/std.global.pdl @@ -1,9 +1,9 @@ #module std.global -func get(in) -> T #builtin -func put(out, T value) -> #type_void #builtin -func fires(#type_portlike) -> bool #builtin -func create(#type_integerlike length) -> T[] #builtin -func length(#type_arraylike array) -> u32 #builtin -func assert(bool condition) -> #type_void #builtin -func print(string message) -> #type_void #builtin \ No newline at end of file +func get(in input) -> T { #builtin } +func put(out output, T value) -> #type_void { #builtin } +func fires(#type_portlike) -> bool { #builtin } +func create(#type_integerlike length) -> T[] { #builtin } +func length(#type_arraylike array) -> u32 { #builtin } +func assert(bool condition) -> #type_void { #builtin } +func print(string message) -> #type_void { #builtin } \ No newline at end of file