From 6717437470eb3e01aa05fa9cbd58e5bc40ac5ba6 2021-03-02 16:14:17 From: MH Date: 2021-03-02 16:14:17 Subject: [PATCH] WIP on bugfixing new visitor --- diff --git a/src/protocol/ast.rs b/src/protocol/ast.rs index 2cf4fc0e434bc25cf1a4035461e4854d9bc90739..262007e63b782f2f69c37715b75092771cd0388a 100644 --- a/src/protocol/ast.rs +++ b/src/protocol/ast.rs @@ -83,7 +83,8 @@ impl FunctionId { pub struct StatementId(Id); #[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)] -pub struct BlockStatementId(StatementId); +// TODO: Remove pub +pub struct BlockStatementId(pub StatementId); impl BlockStatementId { pub fn upcast(self) -> StatementId { @@ -818,6 +819,12 @@ impl Index for Heap { } } +impl IndexMut for Heap { + fn index_mut(&mut self, index: LocalId) -> &mut Self::Output { + self.variables[index.0.0].as_local_mut() + } +} + impl Index for Heap { type Output = Definition; fn index(&self, index: DefinitionId) -> &Self::Output { @@ -913,6 +920,12 @@ impl Index for Heap { } } +impl IndexMut for Heap { + fn index_mut(&mut self, index: IfStatementId) -> &mut Self::Output { + self.statements[(index.0).0].as_if_mut() + } +} + impl Index for Heap { type Output = EndIfStatement; fn index(&self, index: EndIfStatementId) -> &Self::Output { @@ -1527,30 +1540,24 @@ impl Field { } #[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)] -pub enum ScopeVariant { +pub enum Scope { Definition(DefinitionId), Regular(BlockStatementId), Synchronous((SynchronousStatementId, BlockStatementId)), } -// TODO: Cleanup -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -pub struct Scope { - pub variant: ScopeVariant -} - impl Scope { pub fn is_block(&self) -> bool { - match &self.variant { - ScopeVariant::Definition(_) => false, - ScopeVariant::Regular(_) => true, - ScopeVariant::Synchronous(_) => true, + match &self { + Scope::Definition(_) => false, + Scope::Regular(_) => true, + Scope::Synchronous(_) => true, } } pub fn to_block(&self) -> BlockStatementId { - match &self.variant { - ScopeVariant::Regular(id) => *id, - ScopeVariant::Synchronous((_, id)) => *id, + match &self { + Scope::Regular(id) => *id, + Scope::Synchronous((_, id)) => *id, _ => panic!("unable to get BlockStatement from Scope") } } @@ -1565,15 +1572,15 @@ impl VariableScope for Scope { fn parent_scope(&self, h: &Heap) -> Option { match self { Scope::Definition(def) => h[*def].parent_scope(h), - Scope::Block(stmt) => h[*stmt].parent_scope(h), - Scope::Synchronous(stmt) => h[*stmt].parent_scope(h), + Scope::Regular(stmt) => h[*stmt].parent_scope(h), + Scope::Synchronous((stmt, _)) => h[*stmt].parent_scope(h), } } fn get_variable(&self, h: &Heap, id: &Identifier) -> Option { match self { Scope::Definition(def) => h[*def].get_variable(h, id), - Scope::Block(stmt) => h[*stmt].get_variable(h, id), - Scope::Synchronous(stmt) => h[*stmt].get_variable(h, id), + Scope::Regular(stmt) => h[*stmt].get_variable(h, id), + Scope::Synchronous((stmt, _)) => h[*stmt].get_variable(h, id), } } } @@ -1609,6 +1616,12 @@ impl Variable { _ => panic!("Unable to cast `Variable` to `Local`"), } } + pub fn as_local_mut(&mut self) -> &mut Local { + match self { + Variable::Local(result) => result, + _ => panic!("Unable to cast 'Variable' to 'Local'"), + } + } pub fn the_type<'b>(&self, h: &'b Heap) -> &'b Type { match self { Variable::Parameter(param) => &h[param.type_annotation].the_type, @@ -2019,6 +2032,12 @@ impl Statement { _ => panic!("Unable to cast `Statement` to `IfStatement`"), } } + pub fn as_if_mut(&mut self) -> &mut IfStatement { + match self { + Statement::If(result) => result, + _ => panic!("Unable to cast 'Statement' to 'IfStatement'"), + } + } pub fn as_end_if(&self) -> &EndIfStatement { match self { Statement::EndIf(result) => result, @@ -2207,7 +2226,7 @@ impl BlockStatement { // parent block. None } - Scope::Synchronous(parent) => { + Scope::Synchronous((parent, _)) => { // It is always the case that when this function is called, // the parent of a synchronous statement is a block statement: // nested synchronous statements are flagged illegal, @@ -2215,7 +2234,7 @@ impl BlockStatement { // creates the parent_scope references in the first place. Some(h[parent].parent_scope(h).unwrap().to_block()) } - Scope::Block(parent) => { + Scope::Regular(parent) => { // A variable scope is either a definition, sync, or block. Some(parent) } @@ -2413,7 +2432,7 @@ impl SyntaxElement for WhileStatement { pub struct EndWhileStatement { pub this: EndWhileStatementId, // Phase 2: linker - pub start_while: Option, + pub start_while: WhileStatementId, pub position: InputPosition, // of corresponding while pub next: Option, } @@ -2478,13 +2497,14 @@ impl VariableScope for SynchronousStatement { fn parent_scope(&self, _h: &Heap) -> Option { self.parent_scope.clone() } - fn get_variable(&self, h: &Heap, id: &Identifier) -> Option { - for parameter_id in self.parameters.iter() { - let parameter = &h[*parameter_id]; - if parameter.identifier.value == id.value { - return Some(parameter_id.0); - } - } + fn get_variable(&self, _h: &Heap, _id: &Identifier) -> Option { + // TODO: Another case of "where was this used for?" + // for parameter_id in self.parameters.iter() { + // let parameter = &h[*parameter_id]; + // if parameter.identifier.value == id.value { + // return Some(parameter_id.0); + // } + // } None } } diff --git a/src/protocol/containers.rs b/src/protocol/containers.rs deleted file mode 100644 index d0a27eda76f4489eb051aa536b4ff07c57c491f3..0000000000000000000000000000000000000000 --- a/src/protocol/containers.rs +++ /dev/null @@ -1,117 +0,0 @@ -/// Containers.rs -/// -/// Contains specialized containers for the parser/compiler -/// TODO: Actually implement, I really want to remove all of the identifier -/// allocations. - -use std::collections::LinkedList; - -const PAGE_SIZE: usize = 4096; - -struct StringPage { - buffer: [u8; PAGE_SIZE], - remaining: usize, - next_page: Option>, -} - -impl StringPage { - fn new() -> Self{ - Self{ - buffer: [0; PAGE_SIZE], - remaining: PAGE_SIZE, - next_page: None - } - } -} - -/// Custom allocator for strings that are copied and remain valid during the -/// complete compilation phase. May perform multiple allocations but the -/// previously allocated strings remain valid. Because we will usually allocate -/// quite a number of these we will allocate a buffer upon construction of the -/// StringAllocator. -pub(crate) struct StringAllocator { - first_page: Box, - last_page: *mut StringPage, -} - -unsafe impl Send for StringAllocator {} - -impl StringAllocator { - pub(crate) fn new() -> StringAllocator { - let mut page = Box::new(StringPage::new()); - let page_ptr = unsafe { page.as_mut() as *mut StringPage }; - StringAllocator{ - first_page: page, - last_page: page_ptr, - } - } - - pub(crate) fn alloc(&mut self, data: &[u8]) -> Result<&'static str, String> { - let data_len = data.len(); - if data_len > PAGE_SIZE { - return Err(format!( - "string is too large ({} bytes exceeds the maximum of {})", - data_len, PAGE_SIZE - )); - } - - // Because we're doing a copy anyway, we might as well perform the - // UTF-8 checking now. Such that it is safe to do an unchecked - // `from_utf8_unchecked` later. - let data = std::str::from_utf8(data); - if let Err(_) = data { - return Err(format!("invalid utf8-string")); - } - let data = data.unwrap(); - - unsafe { - if data_len > (*self.last_page).remaining { - // Allocate new page - let mut new_page = Box::new(StringPage::new()); - let new_page_ptr = new_page.as_mut() as *mut StringPage; - (*self.last_page).next_page = Some(new_page); - self.last_page = new_page_ptr; - } - - let remaining = (*self.last_page).remaining; - debug_assert!(data_len <= remaining); - let start = PAGE_SIZE - remaining; - (*self.last_page).buffer[start..start+data_len].copy_from_slice(data.as_bytes()); - (*self.last_page).remaining -= data_len; - - Ok(std::str::from_utf8_unchecked(&(*self.last_page).buffer[start..start+data_len])) - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_alloc() { - // Make sure pointers are somewhat correct - let mut alloc = StringAllocator::new(); - assert!(alloc.first_page.next_page.is_none()); - assert_eq!(alloc.first_page.as_ref() as *const StringPage, alloc.last_page); - - // Insert and make page full, should not allocate another page yet - let input = "I am a simple static string"; - let filler = " ".repeat(PAGE_SIZE - input.len()); - let ref_first = alloc.alloc(input.as_bytes()).expect("alloc first"); - let ref_filler = alloc.alloc(filler.as_bytes()).expect("alloc filler"); - assert!(alloc.first_page.next_page.is_none()); - assert_eq!(alloc.first_page.as_ref() as *const StringPage, alloc.last_page); - - let ref_second = alloc.alloc(input.as_bytes()).expect("alloc second"); - - assert!(alloc.first_page.next_page.is_some()); - assert!(alloc.first_page.next_page.as_ref().unwrap().next_page.is_none()); - let last_page_ptr = alloc.first_page.next_page.as_ref().unwrap().as_ref() as *const StringPage; - assert_eq!(last_page_ptr, alloc.last_page); - - assert_eq!(ref_first, input); - assert_eq!(ref_filler, filler); - assert_eq!(ref_second, input); - } -} \ No newline at end of file diff --git a/src/protocol/eval.rs b/src/protocol/eval.rs index 8b0131de87bcb525ea2055ffae180d5de0e2513d..6c7de0873cbf2cdb68d8bb9afad60a9bc439a86b 100644 --- a/src/protocol/eval.rs +++ b/src/protocol/eval.rs @@ -1605,7 +1605,7 @@ pub enum EvalContinuation { Terminal, SyncBlockStart, SyncBlockEnd, - NewComponent(DeclarationId, Vec), + NewComponent(DefinitionId, Vec), BlockFires(Value), BlockGet(Value), Put(Value, Value), @@ -1699,7 +1699,7 @@ impl Prompt { if value.as_boolean().0 { self.position = Some(stmt.body); } else { - self.position = stmt.next.map(|x| x.upcast()); + self.position = stmt.end_while.map(|x| x.upcast()); } Err(EvalContinuation::Stepping) } @@ -1759,7 +1759,12 @@ impl Prompt { args.push(value); } self.position = stmt.next; - Err(EvalContinuation::NewComponent(expr.declaration.unwrap(), args)) + match &expr.method { + Method::Symbolic(symbolic) => { + Err(EvalContinuation::NewComponent(symbolic.definition.unwrap(), args)) + }, + _ => unreachable!("not a symbolic call expression") + } } Statement::Put(stmt) => { // Evaluate port and message diff --git a/src/protocol/inputsource.rs b/src/protocol/inputsource.rs index 858fdf25cd964674da1e9b859a5a6216de1e2aba..60fa628ebe50cf27f3e786243d29465c3f0359f0 100644 --- a/src/protocol/inputsource.rs +++ b/src/protocol/inputsource.rs @@ -16,15 +16,15 @@ pub struct InputSource { static STD_LIB_PDL: &'static [u8] = b" primitive forward(in i, out o) { - while(true) synchronous() put(o, get(i)); + while(true) synchronous put(o, get(i)); } primitive sync(in i, out o) { - while(true) synchronous() if(fires(i)) put(o, get(i)); + while(true) synchronous if(fires(i)) put(o, get(i)); } primitive alternator(in i, out l, out r) { while(true) { - synchronous() if(fires(i)) put(l, get(i)); - synchronous() if(fires(i)) put(r, get(i)); + synchronous if(fires(i)) put(l, get(i)); + synchronous if(fires(i)) put(r, get(i)); } } primitive replicator(in i, out l, out r) { diff --git a/src/protocol/lexer.rs b/src/protocol/lexer.rs index 54a81de9c944626a8b34cc4dacff50302b24f458..d028334b8af496dfe91ed4cbf055a97e99c70542 100644 --- a/src/protocol/lexer.rs +++ b/src/protocol/lexer.rs @@ -343,6 +343,8 @@ impl Lexer<'_> { return Err(self.error_at_pos("Too many namespaces in identifier")); } let new_ident = self.consume_ident()?; + ns_ident.extend(b"::"); + ns_ident.extend(new_ident); num_namespaces += 1; } @@ -1173,8 +1175,7 @@ impl Lexer<'_> { this, position, method, - arguments, - declaration: None, + arguments })) } fn consume_variable_expression( @@ -1300,6 +1301,7 @@ impl Lexer<'_> { position, statements, parent_scope: None, + relative_pos_in_parent: 0, locals: Vec::new(), labels: Vec::new(), }) @@ -1334,18 +1336,21 @@ impl Lexer<'_> { position, type_annotation: from_annotation, identifier: from_identifier, + relative_pos_in_block: 0 }); let to = h.alloc_local(|this| Local { this, position, type_annotation: to_annotation, identifier: to_identifier, + relative_pos_in_block: 0 }); Ok(h.alloc_channel_statement(|this| ChannelStatement { this, position, from, to, + relative_pos_in_block: 0, next: None, })) } @@ -1358,7 +1363,13 @@ impl Lexer<'_> { self.consume_string(b"=")?; self.consume_whitespace(false)?; let initial = self.consume_expression(h)?; - let variable = h.alloc_local(|this| Local { this, position, type_annotation, identifier }); + let variable = h.alloc_local(|this| Local { + this, + position, + type_annotation, + identifier, + relative_pos_in_block: 0 + }); self.consume_whitespace(false)?; self.consume_string(b";")?; Ok(h.alloc_memory_statement(|this| MemoryStatement { @@ -1384,6 +1395,7 @@ impl Lexer<'_> { position, label, body, + relative_pos_in_block: 0, in_sync: None, })) } @@ -1409,7 +1421,7 @@ impl Lexer<'_> { } else { h.alloc_skip_statement(|this| SkipStatement { this, position, next: None }).upcast() }; - Ok(h.alloc_if_statement(|this| IfStatement { this, position, test, true_body, false_body })) + Ok(h.alloc_if_statement(|this| IfStatement { this, position, test, true_body, false_body, end_if: None })) } fn consume_while_statement(&mut self, h: &mut Heap) -> Result { let position = self.source.pos(); @@ -1423,7 +1435,7 @@ impl Lexer<'_> { position, test, body, - next: None, + end_while: None, in_sync: None, })) } @@ -1483,6 +1495,7 @@ impl Lexer<'_> { this, position, body, + end_sync: None, parent_scope: None, })) } diff --git a/src/protocol/library.rs b/src/protocol/library.rs index 76a099e4233301533a7d53d83829181f26c2a02f..76a4f52d86cef48b13ff687ee7e385c6e2f258e5 100644 --- a/src/protocol/library.rs +++ b/src/protocol/library.rs @@ -3,7 +3,7 @@ use crate::protocol::inputsource::*; // TABBED OUT FOR NOW -pub fn get_declarations(h: &mut Heap, i: ImportId) -> Result, ParseError2> { +pub fn get_declarations(_h: &mut Heap, _i: ImportId) -> Result, ParseError2> { todo!("implement me"); // if h[i].value == b"std.reo" { // let mut vec = Vec::new(); diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index 42a3c0b002598c23ce55f4bd5ef548ea59ec414c..23199e60e19c0e195d3ee1f26a3f2255cbf3db7a 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -5,7 +5,6 @@ pub(crate) mod inputsource; // mod lexer; mod library; mod parser; -mod containers; // TODO: Remove when not benchmarking pub(crate) mod ast; @@ -143,11 +142,10 @@ impl ComponentState { EvalContinuation::SyncBlockStart => return NonsyncBlocker::SyncBlockStart, // Not possible to end sync block if never entered one EvalContinuation::SyncBlockEnd => unreachable!(), - EvalContinuation::NewComponent(decl, args) => { + EvalContinuation::NewComponent(definition_id, args) => { // Look up definition (TODO for now, assume it is a definition) let h = &pd.heap; - let def = h[decl].as_defined().definition; - let init_state = ComponentState { prompt: Prompt::new(h, def, &args) }; + let init_state = ComponentState { prompt: Prompt::new(h, definition_id, &args) }; context.new_component(&args, init_state); // Continue stepping continue; diff --git a/src/protocol/parser/depth_visitor.rs b/src/protocol/parser/depth_visitor.rs index b15f88d77adf7153c2cb1db3e40a392cf9c63908..0f48122a628aa8184bcaaf15a2efc675910acddd 100644 --- a/src/protocol/parser/depth_visitor.rs +++ b/src/protocol/parser/depth_visitor.rs @@ -21,10 +21,10 @@ pub(crate) trait Visitor: Sized { fn visit_symbol_definition(&mut self, h: &mut Heap, def: DefinitionId) -> VisitorResult { recursive_symbol_definition(self, h, def) } - fn visit_struct_definition(&mut self, h: &mut Heap, def: StructId) -> VisitorResult { + fn visit_struct_definition(&mut self, _h: &mut Heap, _def: StructId) -> VisitorResult { Ok(()) } - fn visit_enum_definition(&mut self, h: &mut Heap, def: EnumId) -> VisitorResult { + fn visit_enum_definition(&mut self, _h: &mut Heap, _def: EnumId) -> VisitorResult { Ok(()) } fn visit_component_definition(&mut self, h: &mut Heap, def: ComponentId) -> VisitorResult { @@ -385,9 +385,10 @@ fn recursive_synchronous_statement( h: &mut Heap, stmt: SynchronousStatementId, ) -> VisitorResult { - for ¶m in h[stmt].parameters.clone().iter() { - recursive_parameter_as_variable(this, h, param)?; - } + // TODO: Check where this was used for + // for ¶m in h[stmt].parameters.clone().iter() { + // recursive_parameter_as_variable(this, h, param)?; + // } this.visit_statement(h, h[stmt].body) } @@ -894,7 +895,8 @@ impl Visitor for LinkCallExpressions { return Err((id.identifier.position, "Illegal call expression".to_string())); } // Set the corresponding declaration of the call - h[expr].declaration = Some(decl); + // TODO: This should not be necessary anymore once parser is rewritten + // h[expr]. = Some(decl); } // A new statement's call expression may have as arguments function calls let old = self.new_statement; @@ -929,7 +931,7 @@ impl Visitor for BuildScope { // First store the current scope h[stmt].parent_scope = self.scope; // Then move scope down to current block - self.scope = Some(Scope::Block(stmt)); + self.scope = Some(Scope::Regular(stmt)); recursive_block_statement(self, h, stmt)?; // Move scope back up self.scope = old; @@ -945,7 +947,8 @@ impl Visitor for BuildScope { // First store the current scope h[stmt].parent_scope = self.scope; // Then move scope down to current sync - self.scope = Some(Scope::Synchronous(stmt)); + // TODO: Should be legal-ish, but very wrong + self.scope = Some(Scope::Synchronous((stmt, BlockStatementId(stmt.upcast())))); recursive_synchronous_statement(self, h, stmt)?; // Move scope back up self.scope = old; @@ -1066,7 +1069,7 @@ impl Visitor for ResolveVariables { fn visit_block_statement(&mut self, h: &mut Heap, stmt: BlockStatementId) -> VisitorResult { assert!(!self.scope.is_none()); let old = self.scope; - self.scope = Some(Scope::Block(stmt)); + self.scope = Some(Scope::Regular(stmt)); recursive_block_statement(self, h, stmt)?; self.scope = old; Ok(()) @@ -1078,7 +1081,7 @@ impl Visitor for ResolveVariables { ) -> VisitorResult { assert!(!self.scope.is_none()); let old = self.scope; - self.scope = Some(Scope::Synchronous(stmt)); + self.scope = Some(Scope::Synchronous((stmt, BlockStatementId(stmt.upcast())))); // TODO: WRONG! recursive_synchronous_statement(self, h, stmt)?; self.scope = old; Ok(()) @@ -1088,7 +1091,8 @@ impl Visitor for ResolveVariables { h: &mut Heap, expr: VariableExpressionId, ) -> VisitorResult { - let var = self.get_variable(h, &h[expr].identifier)?; + let ident = Identifier{ position: Default::default(), value: h[expr].identifier.value.clone() }; + let var = self.get_variable(h, &ident)?; h[expr].declaration = Some(var); Ok(()) } @@ -1135,7 +1139,7 @@ impl Visitor for LinkStatements { // We allocate a pseudo-statement, which combines both branches into one next statement let position = h[stmt].position; let pseudo = - h.alloc_end_if_statement(|this| EndIfStatement { this, position, next: None }).upcast(); + h.alloc_end_if_statement(|this| EndIfStatement { this, start_if: stmt, position, next: None }).upcast(); assert!(self.prev.is_none()); self.visit_statement(h, h[stmt].true_body)?; if let Some(UniqueStatementId(prev)) = self.prev.take() { @@ -1154,9 +1158,9 @@ impl Visitor for LinkStatements { // We allocate a pseudo-statement, to which the break statement finds its target let position = h[stmt].position; let pseudo = - h.alloc_end_while_statement(|this| EndWhileStatement { this, position, next: None }); + h.alloc_end_while_statement(|this| EndWhileStatement { this, start_while: stmt, position, next: None }); // Update the while's next statement to point to the pseudo-statement - h[stmt].next = Some(pseudo); + h[stmt].end_while = Some(pseudo); assert!(self.prev.is_none()); self.visit_statement(h, h[stmt].body)?; // The body's next statement loops back to the while statement itself @@ -1190,6 +1194,7 @@ impl Visitor for LinkStatements { let pseudo = h .alloc_end_synchronous_statement(|this| EndSynchronousStatement { this, + start_sync: stmt, position, next: None, }) @@ -1400,7 +1405,7 @@ impl Visitor for ResolveLabels { "Illegal break: synchronous statement escape".to_string(), )); } - h[stmt].target = the_while.next; + h[stmt].target = the_while.end_while; Ok(()) } fn visit_continue_statement( diff --git a/src/protocol/parser/functions.rs b/src/protocol/parser/functions.rs deleted file mode 100644 index 19171504b1c0986be18b37190749976c4eda180f..0000000000000000000000000000000000000000 --- a/src/protocol/parser/functions.rs +++ /dev/null @@ -1,97 +0,0 @@ -use crate::protocol::parser::{type_table::*, symbol_table::*, LexedModule}; -use crate::protocol::inputsource::*; -use crate::protocol::ast::*; - -type FnResult = Result<(), ParseError2>; - -pub(crate) struct Ctx<'a> { - module: &'a LexedModule, - heap: &'a mut Heap, - types: &'a TypeTable, - symbols: &'a SymbolTable, -} -pub(crate) struct FunctionParser { - -} - -impl FunctionParser { - pub(crate) fn new() -> Self { - Self{} - } - - pub(crate) fn visit_function_definition(&mut self, ctx: &mut Ctx, id: DefinitionId) -> FnResult { - let body_id = ctx.heap[id].as_function().body; - - // Three passes: - // 1. first pass: breadth first parsing of elements - // 2. second pass: insert any new statments that we queued in the first pass - // 3. third pass: traverse children - - for stmt_id in ctx.heap[body_id].as_block().statements.iter() { - let stmt = &ctx.heap[*stmt_id]; - match stmt { - Statement::Block(block) => { - // Mark for later traversal - }, - Statement::Local(LocalStatement::Channel(stmt)) => { - return Err(ParseError2::new_error(&ctx.module.source, stmt.position, "Illegal channel instantiation in function")); - }, - Statement::Local(LocalStatement::Memory(stmt)) => { - // Resolve type, add to locals - }, - Statement::Skip(skip) => {}, - Statement::Labeled(label) => { - // Add label, then parse statement - }, - Statement::If(stmt) => { - // Mark for later traversal, - // Mark for insertion of "EndIf" - }, - Statement::EndIf(_) => {}, - Statement::While(stmt) => { - // Mark for later traversal - // Mark for insertion of "EndWhile" - }, - Statement::EndWhile(_) => {}, - Statement::Break(stmt) => { - // Perform "break" resolving if labeled. If not labeled then - // use end-while statment - }, - Statement::Continue(stmt) => { - // Perform "continue" resolving if labeled. If not labeled - // then use end-while statement - }, - Statement::Synchronous(stmt) => { - // Illegal! - }, - Statement::EndSynchronous(stmt) => { - // Illegal, but can't possibly be encountered here - }, - Statement::Return(stmt) => { - // Return statement, should be used in control flow analysis - // somehow. Because we need every branch to have a "return" - // call in the language. - }, - Statement::Assert(stmt) => { - // Not allowed in functions? Is allowed in functions? - }, - Statement::Goto(stmt) => { - // Goto label resolving, may not skip definition of - // variables. - }, - Statement::New(stmt) => { - // Illegal in functions? - }, - Statement::Put(stmt) => { - // This really needs to be a builtin call... - }, - Statement::Expression(expr) => { - // Bare expression, we must traverse in order to determine - // if all variables are properly resolved. - } - } - } - - Ok(()) - } -} \ No newline at end of file diff --git a/src/protocol/parser/mod.rs b/src/protocol/parser/mod.rs index 1d71f027d028b5af79f77f74fafd677b8457f851..564e441db1612c0543020e12cb1c093dc00dceec 100644 --- a/src/protocol/parser/mod.rs +++ b/src/protocol/parser/mod.rs @@ -2,10 +2,10 @@ mod depth_visitor; mod symbol_table; mod type_table; mod visitor; -mod functions; use depth_visitor::*; use symbol_table::SymbolTable; +use visitor::{Visitor2, ValidityAndLinkerVisitor}; use type_table::TypeTable; use crate::protocol::ast::*; @@ -14,6 +14,7 @@ use crate::protocol::lexer::*; use std::collections::HashMap; +use crate::protocol::parser::visitor::Ctx; // TODO: @fixme, pub qualifier pub(crate) struct LexedModule { @@ -125,7 +126,7 @@ impl Parser { // Build module lookup } - fn resolve_symbols_and_types(&mut self) -> Result<(), ParseError2> { + fn resolve_symbols_and_types(&mut self) -> Result<(SymbolTable, TypeTable), 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 @@ -186,49 +187,38 @@ impl Parser { // to construct the type table. let type_table = TypeTable::new(&symbol_table, &self.heap, &self.modules)?; - // We should now be able to resolve all definitions and statements - // using those definitions. - // Temporary personal notes - // memory declaration = Statement::Local(Local::Memory(...)) - // -> VariableId - // -> TypeAnnotationId - // -> PrimitiveType::Symbolic variant - // -> Option field - // method call = Expression::Call - // -> Method::Symbolic field - // -> Option field - // TODO: I might not actually want to do this here - module_index = 0; - let mut definition_index = 0; - let mut statement_index = 0; - loop { - if module_index >= self.modules.len() { - break; - } - - let module_root_id = self.modules[module_index].root_id; - let statement_id = { - let root = &self.heap[module_root_id]; - if statement_index >= root. - } - } - - Ok(()) + Ok((symbol_table, type_table)) } // 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; - println!("DEBUG: With root id {:?}\nSource: {}", root_id, String::from_utf8_lossy(&self.modules[0].source.input)); + + let (mut symbol_table, mut type_table) = 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, + }; + let mut visit = ValidityAndLinkerVisitor::new(); + if let Err(err) = visit.visit_module(&mut ctx) { + println!("ERROR:\n{}", err); + return Err(err) + } if let Err((position, message)) = Self::parse_inner(&mut self.heap, root_id) { return Err(ParseError2::new_error(&self.modules[0].source, position, &message)) } + Ok(root_id) } 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)?; @@ -239,8 +229,8 @@ impl Parser { 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)?; + // 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)?; @@ -263,7 +253,7 @@ mod tests { let resource = resource.expect("read testdata filepath"); // println!(" * running: {}", &resource); let path = Path::new(&resource); - let mut source = InputSource::from_file(&path).unwrap(); + 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() { diff --git a/src/protocol/parser/symbol_table.rs b/src/protocol/parser/symbol_table.rs index e96cd2c815c3541895817b00f4f63ae961f587c5..34f390f1ebddd74d95279b272eaee7b7ba5750df 100644 --- a/src/protocol/parser/symbol_table.rs +++ b/src/protocol/parser/symbol_table.rs @@ -114,10 +114,14 @@ impl SymbolTable { ); } } + } else { + lookup_reserve_size += import.symbols.len(); } } } } + + lookup_reserve_size += module_root.definitions.len(); } let mut table = Self{ @@ -266,6 +270,33 @@ impl SymbolTable { } } } + fn find_name(heap: &Heap, root_id: RootId) -> String { + let root = &heap[root_id]; + for pragma_id in &root.pragmas { + match &heap[*pragma_id] { + Pragma::Module(module) => { + return String::from_utf8_lossy(&module.value).to_string() + }, + _ => {}, + } + } + + return String::from("Unknown") + } + + for (k, v) in table.symbol_lookup.iter() { + let key = String::from_utf8_lossy(&k.symbol_name).to_string(); + let value = match v.symbol { + Symbol::Definition((a, b)) => { + let utf8 = String::from_utf8_lossy(&heap[b].identifier().value); + format!("Definition({}) in Root({})", utf8, find_name(heap, a)) + }, + Symbol::Namespace(a) => { + format!("Root({})", find_name(heap, a)) + } + }; + println!("{} => {}", key, value); + } debug_assert_eq!( table.symbol_lookup.len(), lookup_reserve_size, diff --git a/src/protocol/parser/type_table.rs b/src/protocol/parser/type_table.rs index d767de43d42f7ec91a58c1ed80b55bfe3f21a7c9..ea646b9f65182221bb1be23b15a0a4f1cf645896 100644 --- a/src/protocol/parser/type_table.rs +++ b/src/protocol/parser/type_table.rs @@ -204,18 +204,17 @@ impl TypeTable { breadcrumbs.push(Breadcrumb::Linear((module_index, definition_index))); 'resolve_loop: while !breadcrumbs.is_empty() { // Retrieve module, the module's root and the definition - let (module, root, definition_id) = match breadcrumbs.last().unwrap() { + let (module, definition_id) = match breadcrumbs.last().unwrap() { Breadcrumb::Linear((module_index, definition_index)) => { let module = &modules[*module_index]; let root = &heap[module.root_id]; let definition_id = root.definitions[*definition_index]; - (module, root, definition_id) + (module, definition_id) }, Breadcrumb::Jumping((root_id, definition_id)) => { let module = &modules[root_id.0.index as usize]; debug_assert_eq!(module.root_id, *root_id); - let root = &heap[*root_id]; - (module, root, *definition_id) + (module, *definition_id) } }; diff --git a/src/protocol/parser/visitor.rs b/src/protocol/parser/visitor.rs index f9b11e208d13e90a7f03f02d73335b3b6b35d52f..a022f728e9aaf7ec1aafc48079a3bf17f6f3c045 100644 --- a/src/protocol/parser/visitor.rs +++ b/src/protocol/parser/visitor.rs @@ -1,16 +1,15 @@ use crate::protocol::ast::*; use crate::protocol::inputsource::*; -use crate::protocol::library; use crate::protocol::parser::{symbol_table::*, type_table::*, LexedModule}; type Unit = (); pub(crate) type VisitorResult = Result; pub(crate) struct Ctx<'p> { - heap: &'p mut Heap, - module: &'p LexedModule, - symbols: &'p mut SymbolTable, - types: &'p mut TypeTable, + pub heap: &'p mut Heap, + pub module: &'p LexedModule, + pub symbols: &'p mut SymbolTable, + pub types: &'p mut TypeTable, } /// Visitor is a generic trait that will fully walk the AST. The default @@ -31,7 +30,8 @@ pub(crate) trait Visitor2 { root.definitions[def_index] }; - self.visit_definition(ctx, definition_id) + self.visit_definition(ctx, definition_id)?; + def_index += 1; } } @@ -39,48 +39,111 @@ pub(crate) trait Visitor2 { // --- enum matching fn visit_definition(&mut self, ctx: &mut Ctx, id: DefinitionId) -> VisitorResult { match &ctx.heap[id] { - Definition::Enum(def) => self.visit_enum_definition(ctx, def.this), - Definition::Struct(def) => self.visit_struct_definition(ctx, def.this), - Definition::Component(def) => self.visit_component_definition(ctx, def.this), - Definition::Function(def) => self.visit_function_definition(ctx, def.this) + Definition::Enum(def) => { + let def = def.this; + self.visit_enum_definition(ctx, def) + }, + Definition::Struct(def) => { + let def = def.this; + self.visit_struct_definition(ctx, def) + }, + Definition::Component(def) => { + let def = def.this; + self.visit_component_definition(ctx, def) + }, + Definition::Function(def) => { + let def = def.this; + self.visit_function_definition(ctx, def) + } } } // --- enum variant handling - fn visit_enum_definition(&mut self, _ctx: &mut Ctx, id: EnumId) -> VisitorResult { Ok(()) } - fn visit_struct_definition(&mut self, _ctx: &mut Ctx, id: StructId) -> VisitorResult { Ok(()) } - fn visit_component_definition(&mut self, _ctx: &mut Ctx, id: ComponentId) -> VisitorResult { Ok(()) } - fn visit_function_definition(&mut self, _ctx: &mut Ctx, id: FunctionId) -> VisitorResult { Ok(()) } + fn visit_enum_definition(&mut self, _ctx: &mut Ctx, _id: EnumId) -> VisitorResult { Ok(()) } + fn visit_struct_definition(&mut self, _ctx: &mut Ctx, _id: StructId) -> VisitorResult { Ok(()) } + fn visit_component_definition(&mut self, _ctx: &mut Ctx, _id: ComponentId) -> VisitorResult { Ok(()) } + fn visit_function_definition(&mut self, _ctx: &mut Ctx, _id: FunctionId) -> VisitorResult { Ok(()) } // Statements // --- enum matching fn visit_stmt(&mut self, ctx: &mut Ctx, id: StatementId) -> VisitorResult { match &ctx.heap[id] { - Statement::Block(stmt) => self.visit_block_stmt(ctx, stmt.this), - Statement::Local(stmt) => self.visit_local_stmt(ctx, stmt.this), - Statement::Skip(stmt) => self.visit_skip_stmt(ctx, stmt.this), - Statement::Labeled(stmt) => self.visit_labeled_stmt(ctx, stmt.this), - Statement::If(stmt) => self.visit_if_stmt(ctx, stmt.this), + Statement::Block(stmt) => { + let this = stmt.this; + self.visit_block_stmt(ctx, this) + }, + Statement::Local(stmt) => { + let this = stmt.this(); + self.visit_local_stmt(ctx, this) + }, + Statement::Skip(stmt) => { + let this = stmt.this; + self.visit_skip_stmt(ctx, this) + }, + Statement::Labeled(stmt) => { + let this = stmt.this; + self.visit_labeled_stmt(ctx, this) + }, + Statement::If(stmt) => { + let this = stmt.this; + self.visit_if_stmt(ctx, this) + }, Statement::EndIf(_stmt) => Ok(()), - Statement::While(stmt) => self.visit_while_stmt(ctx, stmt.this), + Statement::While(stmt) => { + let this = stmt.this; + self.visit_while_stmt(ctx, this) + }, Statement::EndWhile(_stmt) => Ok(()), - Statement::Break(stmt) => self.visit_break_stmt(ctx, stmt.this), - Statement::Continue(stmt) => self.visit_continue_stmt(ctx, stmt.this), - Statement::Synchronous(stmt) => self.visit_synchronous_stmt(ctx, stmt.this), + Statement::Break(stmt) => { + let this = stmt.this; + self.visit_break_stmt(ctx, this) + }, + Statement::Continue(stmt) => { + let this = stmt.this; + self.visit_continue_stmt(ctx, this) + }, + Statement::Synchronous(stmt) => { + let this = stmt.this; + self.visit_synchronous_stmt(ctx, this) + }, Statement::EndSynchronous(_stmt) => Ok(()), - Statement::Return(stmt) => self.visit_return_stmt(ctx, stmt.this), - Statement::Assert(stmt) => self.visit_assert_stmt(ctx, stmt.this), - Statement::Goto(stmt) => self.visit_goto_stmt(ctx, stmt.this), - Statement::New(stmt) => self.visit_new_stmt(ctx, stmt.this), - Statement::Put(stmt) => self.visit_put_stmt(ctx, stmt.this), - Statement::Expression(stmt) => self.visit_expr_stmt(ctx, stmt.this), + Statement::Return(stmt) => { + let this = stmt.this; + self.visit_return_stmt(ctx, this) + }, + Statement::Assert(stmt) => { + let this = stmt.this; + self.visit_assert_stmt(ctx, this) + }, + Statement::Goto(stmt) => { + let this = stmt.this; + self.visit_goto_stmt(ctx, this) + }, + Statement::New(stmt) => { + let this = stmt.this; + self.visit_new_stmt(ctx, this) + }, + Statement::Put(stmt) => { + let this = stmt.this; + self.visit_put_stmt(ctx, this) + }, + Statement::Expression(stmt) => { + let this = stmt.this; + self.visit_expr_stmt(ctx, this) + } } } fn visit_local_stmt(&mut self, ctx: &mut Ctx, id: LocalStatementId) -> VisitorResult { match &ctx.heap[id] { - LocalStatement::Channel(stmt) => self.visit_local_channel_stmt(ctx, stmt.this), - LocalStatement::Memory(stmt) => self.visit_local_memory_stmt(ctx, stmt.this), + LocalStatement::Channel(stmt) => { + let this = stmt.this; + self.visit_local_channel_stmt(ctx, this) + }, + LocalStatement::Memory(stmt) => { + let this = stmt.this; + self.visit_local_memory_stmt(ctx, this) + }, } } @@ -106,17 +169,50 @@ pub(crate) trait Visitor2 { // --- enum matching fn visit_expr(&mut self, ctx: &mut Ctx, id: ExpressionId) -> VisitorResult { match &ctx.heap[id] { - Expression::Assignment(expr) => self.visit_assignment_expr(ctx, expr.this), - Expression::Conditional(expr) => self.visit_conditional_expr(ctx, expr.this), - Expression::Binary(expr) => self.visit_binary_expr(ctx, expr.this), - Expression::Unary(expr) => self.visit_unary_expr(ctx, expr.this), - Expression::Indexing(expr) => self.visit_indexing_expr(ctx, expr.this), - Expression::Slicing(expr) => self.visit_slicing_expr(ctx, expr.this), - Expression::Select(expr) => self.visit_select_expr(ctx, expr.this), - Expression::Array(expr) => self.visit_array_expr(ctx, expr.this), - Expression::Constant(expr) => self.visit_constant_expr(ctx, expr.this), - Expression::Call(expr) => self.visit_call_expr(ctx, expr.this), - Expression::Variable(expr) => self.visit_variable_expr(ctx, expr.this), + Expression::Assignment(expr) => { + let this = expr.this; + self.visit_assignment_expr(ctx, this) + }, + Expression::Conditional(expr) => { + let this = expr.this; + self.visit_conditional_expr(ctx, this) + } + Expression::Binary(expr) => { + let this = expr.this; + self.visit_binary_expr(ctx, this) + } + Expression::Unary(expr) => { + let this = expr.this; + self.visit_unary_expr(ctx, this) + } + Expression::Indexing(expr) => { + let this = expr.this; + self.visit_indexing_expr(ctx, this) + } + Expression::Slicing(expr) => { + let this = expr.this; + self.visit_slicing_expr(ctx, this) + } + Expression::Select(expr) => { + let this = expr.this; + self.visit_select_expr(ctx, this) + } + Expression::Array(expr) => { + let this = expr.this; + self.visit_array_expr(ctx, this) + } + Expression::Constant(expr) => { + let this = expr.this; + self.visit_constant_expr(ctx, this) + } + Expression::Call(expr) => { + let this = expr.this; + self.visit_call_expr(ctx, this) + } + Expression::Variable(expr) => { + let this = expr.this; + self.visit_variable_expr(ctx, this) + } } } @@ -133,6 +229,7 @@ pub(crate) trait Visitor2 { fn visit_variable_expr(&mut self, _ctx: &mut Ctx, _id: VariableExpressionId) -> VisitorResult { Ok(()) } } +#[derive(PartialEq, Eq)] enum DefinitionType { Primitive, Composite, @@ -159,7 +256,7 @@ enum DefinitionType { /// /// Because of this scheme expressions will not be visited in the breadth-first /// pass. -struct ValidityAndLinkerVisitor { +pub(crate) struct ValidityAndLinkerVisitor { /// `in_sync` is `Some(id)` if the visitor is visiting the children of a /// synchronous statement. A single value is sufficient as nested /// synchronous statements are not allowed @@ -186,7 +283,7 @@ struct ValidityAndLinkerVisitor { } impl ValidityAndLinkerVisitor { - fn new() -> Self { + pub(crate) fn new() -> Self { Self{ in_sync: None, in_while: None, @@ -219,52 +316,31 @@ impl Visitor2 for ValidityAndLinkerVisitor { fn visit_component_definition(&mut self, ctx: &mut Ctx, id: ComponentId) -> VisitorResult { self.reset_state(); - let block_id = { - let def = &ctx.heap[id]; - match def.variant { - ComponentVariant::Primitive => self.def_type = DefinitionType::Primitive, - ComponentVariant::Composite => self.def_type = DefinitionType::Composite, - } - - let body = ctx.heap[def.body].as_block_mut(); - - self.statement_buffer.extend_from_slice(&body.statements); - self.statement_stack_indices.push(0); - body.this + self.def_type = match &ctx.heap[id].variant { + ComponentVariant::Primitive => DefinitionType::Primitive, + ComponentVariant::Composite => DefinitionType::Composite, }; - - self.cur_scope = Some(Scope { - variant: ScopeVariant::Definition(id.upcast()), - }); + self.cur_scope = Some(Scope::Definition(id.upcast())); + let body_id = ctx.heap[id].body; self.performing_breadth_pass = true; - self.visit_block_stmt(ctx, block_id)?; + self.visit_stmt(ctx, body_id)?; self.performing_breadth_pass = false; - self.visit_block_stmt(ctx, block_id) + self.visit_stmt(ctx, body_id) } fn visit_function_definition(&mut self, ctx: &mut Ctx, id: FunctionId) -> VisitorResult { self.reset_state(); // Set internal statement indices - let block_id = { - let def = &ctx.heap[id]; - self.def_type = DefinitionType::Function; - let body = ctx.heap[def.body].as_block_mut(); - - self.statement_buffer.extend_from_slice(&body.statements); - self.statement_stack_indices.push(0); - body.this - }; - - self.cur_scope = Some(Scope { - variant: ScopeVariant::Definition(id.upcast()), - }); + self.def_type = DefinitionType::Function; + self.cur_scope = Some(Scope::Definition(id.upcast())); + let body_id = ctx.heap[id].body; self.performing_breadth_pass = true; - self.visit_block_stmt(ctx, block_id)?; + self.visit_stmt(ctx, body_id)?; self.performing_breadth_pass = false; - self.visit_block_stmt(ctx, block_id) + self.visit_stmt(ctx, body_id) } //-------------------------------------------------------------------------- @@ -277,9 +353,8 @@ impl Visitor2 for ValidityAndLinkerVisitor { fn visit_local_memory_stmt(&mut self, ctx: &mut Ctx, id: MemoryStatementId) -> VisitorResult { if self.performing_breadth_pass { - let stmt = &ctx.heap[id]; - stmt.relative_pos_in_block = self.relative_pos_in_block; - self.checked_local_add(ctx, stmt.variable)?; + let variable_id = ctx.heap[id].variable; + self.checked_local_add(ctx, self.relative_pos_in_block, variable_id)?; } else { self.visit_expr(ctx, ctx.heap[id].initial)?; } @@ -287,28 +362,28 @@ impl Visitor2 for ValidityAndLinkerVisitor { Ok(()) } - fn visit_labeled_stmt(&mut self, ctx: &mut Ctx, id: LabeledStatementId) -> VisitorResult { + fn visit_local_channel_stmt(&mut self, ctx: &mut Ctx, id: ChannelStatementId) -> VisitorResult { if self.performing_breadth_pass { - // Retrieve scope - let scope = self.cur_scope.as_ref().unwrap(); - debug_assert!(scope.statement.is_some(), "expected scope statement at labeled stmt"); - debug_assert_eq!( - scope.variant == ScopeVariant::Synchronous, - self.in_sync.is_some(), - "in synchronous scope variant, but 'in_sync' not set" - ); + let (from_id, to_id) = { + let stmt = &ctx.heap[id]; + (stmt.from, stmt.to) + }; + self.checked_local_add(ctx, self.relative_pos_in_block, from_id)?; + self.checked_local_add(ctx, self.relative_pos_in_block, to_id)?; + } + Ok(()) + } + + fn visit_labeled_stmt(&mut self, ctx: &mut Ctx, id: LabeledStatementId) -> VisitorResult { + if self.performing_breadth_pass { // Add label to block lookup self.checked_label_add(ctx, id)?; // Modify labeled statement itself let labeled = &mut ctx.heap[id]; labeled.relative_pos_in_block = self.relative_pos_in_block; - labeled.in_sync = if scope.variant == ScopeVariant::Synchronous { - self.in_sync.clone() - } else { - None - }; + labeled.in_sync = self.in_sync.clone(); } let body_id = ctx.heap[id].body; @@ -347,17 +422,11 @@ impl Visitor2 for ValidityAndLinkerVisitor { fn visit_while_stmt(&mut self, ctx: &mut Ctx, id: WhileStatementId) -> VisitorResult { if self.performing_breadth_pass { - let scope = self.cur_scope.as_ref().unwrap(); let position = ctx.heap[id].position; - debug_assert_eq!( - scope.variant == ScopeVariant::Synchronous, - self.in_sync.is_some(), - "in synchronous scope variant, but 'in_sync' not set" - ); let end_while_id = ctx.heap.alloc_end_while_statement(|this| { EndWhileStatement { this, - start_while: Some(id), + start_while: id, position, next: None, } @@ -417,19 +486,19 @@ impl Visitor2 for ValidityAndLinkerVisitor { fn visit_synchronous_stmt(&mut self, ctx: &mut Ctx, id: SynchronousStatementId) -> VisitorResult { if self.performing_breadth_pass { // Check for validity of synchronous statement - let cur_sync = &ctx.heap[id]; + let cur_sync_position = ctx.heap[id].position; if self.in_sync.is_some() { // Nested synchronous statement let old_sync = &ctx.heap[self.in_sync.unwrap()]; return Err( - ParseError2::new_error(&ctx.module.source, cur_sync.position, "Illegal nested synchronous statement") + ParseError2::new_error(&ctx.module.source, cur_sync_position, "Illegal nested synchronous statement") .with_postfixed_info(&ctx.module.source, old_sync.position, "It is nested in this synchronous statement") ); } if self.def_type != DefinitionType::Primitive { return Err(ParseError2::new_error( - &ctx.module.source, cur_sync.position, + &ctx.module.source, cur_sync_position, "Synchronous statements may only be used in primitive components" )); } @@ -437,7 +506,7 @@ impl Visitor2 for ValidityAndLinkerVisitor { // Append SynchronousEnd pseudo-statement let sync_end_id = ctx.heap.alloc_end_synchronous_statement(|this| EndSynchronousStatement{ this, - position: stmt.position, + position: cur_sync_position, start_sync: id, next: None, }); @@ -445,8 +514,9 @@ impl Visitor2 for ValidityAndLinkerVisitor { sync_start.end_sync = Some(sync_end_id); self.insert_buffer.push((self.relative_pos_in_block + 1, sync_end_id.upcast())); } else { + let sync_body = ctx.heap[id].body; let old = self.in_sync.replace(id); - self.visit_stmt_with_hint(ctx, stmt.body, Some(id))?; + self.visit_stmt_with_hint(ctx, sync_body, Some(id))?; self.in_sync = old; } @@ -490,7 +560,8 @@ impl Visitor2 for ValidityAndLinkerVisitor { ); } } else { - self.visit_expr(ctx, stmt.expression)?; + let expr_id = stmt.expression; + self.visit_expr(ctx, expr_id)?; } Ok(()) @@ -501,9 +572,8 @@ impl Visitor2 for ValidityAndLinkerVisitor { // Must perform goto label resolving after the breadth pass, this // way we are able to find all the labels in current and outer // scopes. - let goto_stmt = &mut ctx.heap[id]; - let target_id = self.find_label(ctx, &goto_stmt.label)?; - goto_stmt.target = Some(target_id); + let target_id = self.find_label(ctx, &ctx.heap[id].label)?; + ctx.heap[id].target = Some(target_id); let target = &ctx.heap[target_id]; if self.in_sync != target.in_sync { @@ -511,6 +581,7 @@ impl Visitor2 for ValidityAndLinkerVisitor { // nested sync statements are not allowed so if the value does // not match, then we must be inside a sync scope debug_assert!(self.in_sync.is_some()); + let goto_stmt = &ctx.heap[id]; let sync_stmt = &ctx.heap[self.in_sync.unwrap()]; return Err( ParseError2::new_error(&ctx.module.source, goto_stmt.position, "Goto may not escape the surrounding synchronous block") @@ -527,8 +598,9 @@ impl Visitor2 for ValidityAndLinkerVisitor { if self.performing_breadth_pass { // TODO: Cleanup error messages, can be done cleaner // Make sure new statement occurs within a composite component - let new_stmt = &ctx.heap[id]; + let call_expr_id = ctx.heap[id].expression; if self.def_type != DefinitionType::Composite { + let new_stmt = &ctx.heap[id]; return Err( ParseError2::new_error(&ctx.module.source, new_stmt.position, "Instantiating components may only be done in composite components") ); @@ -536,35 +608,33 @@ impl Visitor2 for ValidityAndLinkerVisitor { // No fancy recursive parsing, must be followed by a call expression let definition_id = { - let call_expr = &ctx.heap[new_stmt.expression]; - if let Expression::Call(call_expr) = call_expr { - if let Method::Symbolic(symbolic) = &call_expr.method { - // Resolve method - let (symbol, iter) = ctx.symbols.resolve_namespaced_symbol(ctx.module.root_id, &symbolic.identifier)?; - if iter.num_remaining() != 0 { - return Err( - ParseError2::new_error(&ctx.module.source, symbolic.identifier.position, "Unknown component") - ) - } + let call_expr = &ctx.heap[call_expr_id]; + if let Method::Symbolic(symbolic) = &call_expr.method { + // Resolve method + let maybe_symbol = ctx.symbols.resolve_namespaced_symbol(ctx.module.root_id, &symbolic.identifier); + if maybe_symbol.is_none() { + return Err(ParseError2::new_error(&ctx.module.source, symbolic.identifier.position, "Unknown component")); + } + let (symbol, iter) = maybe_symbol.unwrap(); + if iter.num_remaining() != 0 { + return Err( + ParseError2::new_error(&ctx.module.source, symbolic.identifier.position, "Unknown component") + ) + } - match symbol.symbol { - Symbol::Namespace(_) => return Err( - ParseError2::new_error(&ctx.module.source, symbolic.identifier.position, "Unknown component") - .with_postfixed_info(&ctx.module.source, symbol.position, "The identifier points to this import") - ), - Symbol::Definition((target_root_id, target_definition_id)) => { - match &ctx.heap[target_definition_id] { - Definition::Component(_) => target_definition_id, - _ => return Err( - ParseError2::new_error(&ctx.module.source, symbolic.identifier.position, "Must instantiate a component") - ) - } + match symbol.symbol { + Symbol::Namespace(_) => return Err( + ParseError2::new_error(&ctx.module.source, symbolic.identifier.position, "Unknown component") + .with_postfixed_info(&ctx.module.source, symbol.position, "The identifier points to this import") + ), + Symbol::Definition((_target_root_id, target_definition_id)) => { + match &ctx.heap[target_definition_id] { + Definition::Component(_) => target_definition_id, + _ => return Err( + ParseError2::new_error(&ctx.module.source, symbolic.identifier.position, "Must instantiate a component") + ) } } - } else { - return Err( - ParseError2::new_error(&ctx.module.source, call_expr.position, "Must instantiate a component") - ); } } else { return Err( @@ -575,7 +645,7 @@ impl Visitor2 for ValidityAndLinkerVisitor { // Modify new statement's symbolic call to point to the appropriate // definition. - let call_expr = &mut ctx.heap[new_stmt.expression]; + let call_expr = &mut ctx.heap[call_expr_id]; match &mut call_expr.method { Method::Symbolic(method) => method.definition = Some(definition_id), _ => unreachable!() @@ -597,8 +667,10 @@ impl Visitor2 for ValidityAndLinkerVisitor { } } else { let put_stmt = &ctx.heap[id]; - self.visit_expr(ctx, put_stmt.port)?; - self.visit_expr(ctx, put_stmt.message)?; + let port = put_stmt.port; + let message = put_stmt.message; + self.visit_expr(ctx, port)?; + self.visit_expr(ctx, message)?; } Ok(()) @@ -606,8 +678,8 @@ impl Visitor2 for ValidityAndLinkerVisitor { fn visit_expr_stmt(&mut self, ctx: &mut Ctx, id: ExpressionStatementId) -> VisitorResult { if !self.performing_breadth_pass { - let expr = &ctx.heap[id]; - self.visit_expr(ctx, expr.expression)?; + let expr_id = ctx.heap[id].expression; + self.visit_expr(ctx, expr_id)?; } Ok(()) @@ -626,32 +698,39 @@ impl Visitor2 for ValidityAndLinkerVisitor { fn visit_conditional_expr(&mut self, ctx: &mut Ctx, id: ConditionalExpressionId) -> VisitorResult { debug_assert!(!self.performing_breadth_pass); let conditional_expr = &ctx.heap[id]; - self.visit_expr(ctx, conditional_expr.test)?; - self.visit_expr(ctx, conditional_expr.true_expression)?; - self.visit_expr(ctx, conditional_expr.false_expression)?; + let test_expr_id = conditional_expr.test; + let true_expr_id = conditional_expr.true_expression; + let false_expr_id = conditional_expr.false_expression; + self.visit_expr(ctx, test_expr_id)?; + self.visit_expr(ctx, true_expr_id)?; + self.visit_expr(ctx, false_expr_id)?; Ok(()) } fn visit_binary_expr(&mut self, ctx: &mut Ctx, id: BinaryExpressionId) -> VisitorResult { debug_assert!(!self.performing_breadth_pass); let binary_expr = &ctx.heap[id]; - self.visit_expr(ctx, binary_expr.left)?; - self.visit_expr(ctx, binary_expr.right)?; + let left_expr_id = binary_expr.left; + let right_expr_id = binary_expr.right; + self.visit_expr(ctx, left_expr_id)?; + self.visit_expr(ctx, right_expr_id)?; Ok(()) } fn visit_unary_expr(&mut self, ctx: &mut Ctx, id: UnaryExpressionId) -> VisitorResult { debug_assert!(!self.performing_breadth_pass); - let unary_expr = &ctx.heap[id]; - self.visit_expr(ctx, unary_expr.expression)?; + let expr_id = ctx.heap[id].expression; + self.visit_expr(ctx, expr_id)?; Ok(()) } fn visit_indexing_expr(&mut self, ctx: &mut Ctx, id: IndexingExpressionId) -> VisitorResult { debug_assert!(!self.performing_breadth_pass); let indexing_expr = &ctx.heap[id]; - self.visit_expr(ctx, indexing_expr.subject)?; - self.visit_expr(ctx, indexing_expr.index)?; + let subject_expr_id = indexing_expr.subject; + let index_expr_id = indexing_expr.index; + self.visit_expr(ctx, subject_expr_id)?; + self.visit_expr(ctx, index_expr_id)?; Ok(()) } @@ -660,9 +739,12 @@ impl Visitor2 for ValidityAndLinkerVisitor { // TODO: Same as the select expression: slicing depends on the type of // the thing that is being sliced. let slicing_expr = &ctx.heap[id]; - self.visit_expr(ctx, slicing_expr.subject)?; - self.visit_expr(ctx, slicing_expr.from_index)?; - self.visit_expr(ctx, slicing_expr.to_index)?; + let subject_expr_id = slicing_expr.subject; + let from_expr_id = slicing_expr.from_index; + let to_expr_id = slicing_expr.to_index; + self.visit_expr(ctx, subject_expr_id)?; + self.visit_expr(ctx, from_expr_id)?; + self.visit_expr(ctx, to_expr_id)?; Ok(()) } @@ -673,8 +755,8 @@ impl Visitor2 for ValidityAndLinkerVisitor { // int i = some_call_that_returns_a_struct(5, 2).field_of_struct // We could rule out some things (of which we're sure what the type is) // but it seems better to do this later - let select_expr = &ctx.heap[id]; - self.visit_expr(ctx, select_expr.subject)?; + let expr_id = ctx.heap[id].subject; + self.visit_expr(ctx, expr_id)?; Ok(()) } @@ -682,13 +764,13 @@ impl Visitor2 for ValidityAndLinkerVisitor { fn visit_array_expr(&mut self, ctx: &mut Ctx, id: ArrayExpressionId) -> VisitorResult { debug_assert!(!self.performing_breadth_pass); let array_expr = &ctx.heap[id]; - for field in &array_expr.elements { - self.visit_expr(ctx, *field)?; + for field_expr_id in array_expr.elements.clone() { // TODO: @performance + self.visit_expr(ctx, field_expr_id)?; } Ok(()) } - fn visit_constant_expr(&mut self, ctx: &mut Ctx, id: ConstantExpressionId) -> VisitorResult { + fn visit_constant_expr(&mut self, _ctx: &mut Ctx, _id: ConstantExpressionId) -> VisitorResult { debug_assert!(!self.performing_breadth_pass); Ok(()) } @@ -760,6 +842,7 @@ impl Visitor2 for ValidityAndLinkerVisitor { debug_assert!(!self.performing_breadth_pass); let var_expr = &ctx.heap[id]; + println!("DEBUG: Finding variable {}", String::from_utf8_lossy(&var_expr.identifier.value)); let variable_id = self.find_variable(ctx, self.relative_pos_in_block, &var_expr.identifier)?; let var_expr = &mut ctx.heap[id]; var_expr.declaration = Some(variable_id); @@ -774,8 +857,9 @@ impl ValidityAndLinkerVisitor { //-------------------------------------------------------------------------- fn visit_stmt_with_hint(&mut self, ctx: &mut Ctx, id: StatementId, hint: Option) -> VisitorResult { - if let Statement::Block(block) = &ctx.heap[id] { - self.visit_block_stmt_with_hint(ctx, block.this, hint) + if let Statement::Block(block_stmt) = &ctx.heap[id] { + let block_id = block_stmt.this; + self.visit_block_stmt_with_hint(ctx, block_id, hint) } else { self.visit_stmt(ctx, id) } @@ -794,14 +878,12 @@ impl ValidityAndLinkerVisitor { // We may descend into children of this block. However, this is // where we first perform a breadth-first pass + // TODO: This is where crap goes wrong! If we are performing the first + // breadth pass then we should take care of the scopes properly! self.performing_breadth_pass = true; let old_scope = self.cur_scope.replace(match hint { - Some(sync_id) => Scope{ - variant: ScopeVariant::Synchronous((sync_id, id)), - }, - None => Scope{ - variant: ScopeVariant::Regular(id) - } + Some(sync_id) => Scope::Synchronous((sync_id, id)), + None => Scope::Regular(id), }); let first_statement_index = self.statement_buffer.len(); @@ -848,7 +930,9 @@ impl ValidityAndLinkerVisitor { // Utilities //-------------------------------------------------------------------------- - fn checked_local_add(&mut self, ctx: &mut Ctx, id: LocalId) -> Result<(), ParseError2> { + /// Adds a local variable to the current scope. It will also annotate the + /// `Local` in the AST with its relative position in the block. + fn checked_local_add(&mut self, ctx: &mut Ctx, relative_pos: u32, id: LocalId) -> Result<(), ParseError2> { debug_assert!(self.cur_scope.is_some()); // Make sure we do not conflict with any global symbols @@ -862,6 +946,9 @@ impl ValidityAndLinkerVisitor { } } + let local = &mut ctx.heap[id]; + local.relative_pos_in_block = relative_pos; + // Make sure we do not shadow any variables in any of the scopes. Note // that variables in parent scopes may be declared later let local = &ctx.heap[id]; @@ -876,7 +963,7 @@ impl ValidityAndLinkerVisitor { // Position check in case another variable with the same name // is defined in a higher-level scope, but later than the scope // in which the current variable resides. - if local_relative_pos >= other_local.relative_pos_in_block && local.identifier.value == other_local.identifier.pos { + if local_relative_pos > other_local.relative_pos_in_block && local.identifier.value == other_local.identifier.value { // Collision within this scope return Err( ParseError2::new_error(&ctx.module.source, local.position, "Local variable name conflicts with another variable") @@ -886,11 +973,11 @@ impl ValidityAndLinkerVisitor { } // Current scope is fine, move to parent scope if any - debug_assert!(scope.parent.is_some(), "block scope does not have a parent"); - scope = scope.parent.as_ref().unwrap(); - if let ScopeVariant::Definition(definition_id) = scope.variant { + debug_assert!(block.parent_scope.is_some(), "block scope does not have a parent"); + scope = block.parent_scope.as_ref().unwrap(); + if let Scope::Definition(definition_id) = scope { // At outer scope, check parameters of function/component - for parameter_id in ctx.heap[definition_id].parameters() { + for parameter_id in ctx.heap[*definition_id].parameters() { let parameter = &ctx.heap[*parameter_id]; if local.identifier.value == parameter.identifier.value { return Err( @@ -930,10 +1017,12 @@ impl ValidityAndLinkerVisitor { // No need to use iterator over namespaces if here let mut scope = self.cur_scope.as_ref().unwrap(); loop { + println!("DEBUG: Looking at block {}...", scope.); debug_assert!(scope.is_block()); let block = &ctx.heap[scope.to_block()]; for local_id in &block.locals { let local = &ctx.heap[*local_id]; + println!("DEBUG: With local {}", String::from_utf8_lossy(&local.identifier.value)); if local.relative_pos_in_block < relative_pos && local.identifier.value == identifier.value { return Ok(local_id.upcast()); } @@ -943,9 +1032,9 @@ impl ValidityAndLinkerVisitor { scope = block.parent_scope.as_ref().unwrap(); if !scope.is_block() { // Definition scope, need to check arguments to definition - match scope.variant { - ScopeVariant::Definition(definition_id) => { - let definition = &ctx.heap[definition_id]; + match scope { + Scope::Definition(definition_id) => { + let definition = &ctx.heap[*definition_id]; for parameter_id in definition.parameters() { let parameter = &ctx.heap[*parameter_id]; if parameter.identifier.value == identifier.value { @@ -1035,8 +1124,8 @@ impl ValidityAndLinkerVisitor { } } - debug_assert!(scope.parent.is_some(), "block scope does not have a parent"); - scope = scope.parent.as_ref().unwrap(); + debug_assert!(block.parent_scope.is_some(), "block scope does not have a parent"); + scope = block.parent_scope.as_ref().unwrap(); if !scope.is_block() { return Err(ParseError2::new_error(&ctx.module.source, identifier.position, "Could not find this label")); } @@ -1057,8 +1146,9 @@ impl ValidityAndLinkerVisitor { return true; } - debug_assert!(scope.parent.is_some(), "block scope does not have a parent"); - scope = scope.parent.as_ref().unwrap(); + let block = &ctx.heap[block]; + debug_assert!(block.parent_scope.is_some(), "block scope does not have a parent"); + scope = block.parent_scope.as_ref().unwrap(); if !scope.is_block() { return false; } @@ -1078,7 +1168,7 @@ impl ValidityAndLinkerVisitor { // Make sure break target is a while statement let target = &ctx.heap[target_id]; - if let Statement::While(target_stmt) = &target.body { + if let Statement::While(target_stmt) = &ctx.heap[target.body] { // Even though we have a target while statement, the break might not be // present underneath this particular labeled while statement if !self.has_parent_while_scope(ctx, target_stmt.this) { diff --git a/src/runtime/tests.rs b/src/runtime/tests.rs index ceb3b85c0c02de9473d7e7c3de0b24850cc9ffb0..ae32b8c4e0008ad3255cb2b07642dbbe6237b64c 100644 --- a/src/runtime/tests.rs +++ b/src/runtime/tests.rs @@ -38,7 +38,7 @@ fn file_logged_configured_connector( } static MINIMAL_PDL: &'static [u8] = b" primitive together(in ia, in ib, out oa, out ob){ - while(true) synchronous() { + while(true) synchronous { if(fires(ia)) { put(oa, get(ia)); put(ob, get(ib)); @@ -1291,7 +1291,7 @@ fn for_msg_byte() { while(i<8) { msg m = create(1); m[0] = i; - synchronous() put(o, m); + synchronous put(o, m); i++; } }