From ca97483c6ec7bfa76d74aafd7745ed097e8b64c4 2021-03-04 18:26:40 From: MH Date: 2021-03-04 18:26:40 Subject: [PATCH] rewritten parser to use symbol/type table --- diff --git a/notes_max.md b/notes_max.md new file mode 100644 index 0000000000000000000000000000000000000000..34bda06763a5e4a744378997eaa7a6b777e76a8f --- /dev/null +++ b/notes_max.md @@ -0,0 +1,3 @@ +# Noteworthy changes + +- `if`, `while`, `synchronous`, `function`, `primitive` and `composite` body statements, if not yet a block, are all converted into a block for simpler parsing/compiling. \ No newline at end of file diff --git a/src/protocol/ast.rs b/src/protocol/ast.rs index 504ab1513d281316bd0e88d13b3d33ece5393364..aad546039890c93261d632c78ff150074333682f 100644 --- a/src/protocol/ast.rs +++ b/src/protocol/ast.rs @@ -202,7 +202,7 @@ impl SynchronousStatementId { } #[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)] -pub struct EndSynchronousStatementId(StatementId); +pub struct EndSynchronousStatementId(pub(crate) StatementId); impl EndSynchronousStatementId { pub fn upcast(self) -> StatementId { @@ -211,7 +211,7 @@ impl EndSynchronousStatementId { } #[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)] -pub struct ReturnStatementId(StatementId); +pub struct ReturnStatementId(pub(crate) StatementId); impl ReturnStatementId { pub fn upcast(self) -> StatementId { @@ -220,7 +220,7 @@ impl ReturnStatementId { } #[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)] -pub struct AssertStatementId(StatementId); +pub struct AssertStatementId(pub(crate) StatementId); impl AssertStatementId { pub fn upcast(self) -> StatementId { @@ -229,7 +229,7 @@ impl AssertStatementId { } #[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)] -pub struct GotoStatementId(StatementId); +pub struct GotoStatementId(pub(crate) StatementId); impl GotoStatementId { pub fn upcast(self) -> StatementId { @@ -238,7 +238,7 @@ impl GotoStatementId { } #[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)] -pub struct NewStatementId(StatementId); +pub struct NewStatementId(pub(crate) StatementId); impl NewStatementId { pub fn upcast(self) -> StatementId { @@ -247,7 +247,7 @@ impl NewStatementId { } #[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)] -pub struct PutStatementId(StatementId); +pub struct PutStatementId(pub(crate) StatementId); impl PutStatementId { pub fn upcast(self) -> StatementId { @@ -256,7 +256,7 @@ impl PutStatementId { } #[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)] -pub struct ExpressionStatementId(StatementId); +pub struct ExpressionStatementId(pub(crate) StatementId); impl ExpressionStatementId { pub fn upcast(self) -> StatementId { @@ -265,10 +265,10 @@ impl ExpressionStatementId { } #[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)] -pub struct ExpressionId(Id); +pub struct ExpressionId(pub(crate) Id); #[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)] -pub struct AssignmentExpressionId(ExpressionId); +pub struct AssignmentExpressionId(pub(crate) ExpressionId); impl AssignmentExpressionId { pub fn upcast(self) -> ExpressionId { @@ -277,7 +277,7 @@ impl AssignmentExpressionId { } #[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)] -pub struct ConditionalExpressionId(ExpressionId); +pub struct ConditionalExpressionId(pub(crate) ExpressionId); impl ConditionalExpressionId { pub fn upcast(self) -> ExpressionId { @@ -286,7 +286,7 @@ impl ConditionalExpressionId { } #[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)] -pub struct BinaryExpressionId(ExpressionId); +pub struct BinaryExpressionId(pub(crate) ExpressionId); impl BinaryExpressionId { pub fn upcast(self) -> ExpressionId { @@ -295,7 +295,7 @@ impl BinaryExpressionId { } #[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)] -pub struct UnaryExpressionId(ExpressionId); +pub struct UnaryExpressionId(pub(crate) ExpressionId); impl UnaryExpressionId { pub fn upcast(self) -> ExpressionId { @@ -304,7 +304,7 @@ impl UnaryExpressionId { } #[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)] -pub struct IndexingExpressionId(ExpressionId); +pub struct IndexingExpressionId(pub(crate) ExpressionId); impl IndexingExpressionId { pub fn upcast(self) -> ExpressionId { @@ -313,7 +313,7 @@ impl IndexingExpressionId { } #[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)] -pub struct SlicingExpressionId(ExpressionId); +pub struct SlicingExpressionId(pub(crate) ExpressionId); impl SlicingExpressionId { pub fn upcast(self) -> ExpressionId { @@ -322,7 +322,7 @@ impl SlicingExpressionId { } #[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)] -pub struct SelectExpressionId(ExpressionId); +pub struct SelectExpressionId(pub(crate) ExpressionId); impl SelectExpressionId { pub fn upcast(self) -> ExpressionId { @@ -331,7 +331,7 @@ impl SelectExpressionId { } #[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)] -pub struct ArrayExpressionId(ExpressionId); +pub struct ArrayExpressionId(pub(crate) ExpressionId); impl ArrayExpressionId { pub fn upcast(self) -> ExpressionId { @@ -340,7 +340,7 @@ impl ArrayExpressionId { } #[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)] -pub struct ConstantExpressionId(ExpressionId); +pub struct ConstantExpressionId(pub(crate) ExpressionId); impl ConstantExpressionId { pub fn upcast(self) -> ExpressionId { @@ -349,7 +349,7 @@ impl ConstantExpressionId { } #[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)] -pub struct CallExpressionId(ExpressionId); +pub struct CallExpressionId(pub(crate) ExpressionId); impl CallExpressionId { pub fn upcast(self) -> ExpressionId { @@ -358,7 +358,7 @@ impl CallExpressionId { } #[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)] -pub struct VariableExpressionId(ExpressionId); +pub struct VariableExpressionId(pub(crate) ExpressionId); impl VariableExpressionId { pub fn upcast(self) -> ExpressionId { diff --git a/src/protocol/ast_printer.rs b/src/protocol/ast_printer.rs index 3b3bed69397c541960531b11c2ebae411f07155b..bba45c7d5962fbd59898c2641c97a304d85fa979 100644 --- a/src/protocol/ast_printer.rs +++ b/src/protocol/ast_printer.rs @@ -1,4 +1,4 @@ -use std::fmt::{Display, Write}; +use std::fmt::{Debug, Display, Write}; use std::io::Write as IOWrite; use super::ast::*; @@ -52,14 +52,131 @@ const PREFIX_CONST_EXPR_ID: &'static str = "ECns"; const PREFIX_CALL_EXPR_ID: &'static str = "ECll"; const PREFIX_VARIABLE_EXPR_ID: &'static str = "EVar"; +struct KV<'a> { + buffer: &'a mut String, + prefix: Option<(&'static str, u32)>, + indent: usize, + temp_key: &'a mut String, + temp_val: &'a mut String, +} + +impl<'a> KV<'a> { + fn new(buffer: &'a mut String, temp_key: &'a mut String, temp_val: &'a mut String, indent: usize) -> Self { + temp_key.clear(); + temp_val.clear(); + KV{ + buffer, + prefix: None, + indent, + temp_key, + temp_val + } + } + + fn with_id(mut self, prefix: &'static str, id: u32) -> Self { + self.prefix = Some((prefix, id)); + self + } + + fn with_s_key(self, key: &str) -> Self { + self.temp_key.push_str(key); + self + } + + fn with_d_key(mut self, key: &D) -> Self { + write!(&mut self.temp_key, "{}", key); + self + } + + fn with_s_val(self, val: &str) -> Self { + self.temp_val.push_str(val); + self + } + + fn with_disp_val(mut self, val: &D) -> Self { + write!(&mut self.temp_val, "{}", val); + self + } + + fn with_debug_val(mut self, val: &D) -> Self { + write!(&mut self.temp_val, "{:?}", val); + self + } + + fn with_ascii_val(self, val: &[u8]) -> Self { + self.temp_val.write_str(&*String::from_utf8_lossy(val)); + self + } + + fn with_opt_disp_val(mut self, val: Option<&D>) -> Self { + match val { + Some(v) => { write!(&mut self.temp_val, "Some({})", v); }, + None => { self.temp_val.write_str("None"); } + } + self + } + + fn with_opt_ascii_val(self, val: Option<&[u8]>) -> Self { + match val { + Some(v) => { + self.temp_val.write_str("Some("); + self.temp_val.write_str(&*String::from_utf8_lossy(v)); + self.temp_val.write_char(')'); + }, + None => { + self.temp_val.write_str("None"); + } + } + self + } + + fn with_custom_val(mut self, val_fn: F) -> Self { + val_fn(&mut self.temp_val); + self + } +} + +impl<'a> Drop for KV<'a> { + fn drop(&mut self) { + // Prefix and indent + if let Some((prefix, id)) = &self.prefix { + write!(&mut self.buffer, "{}[{:04}] ", prefix, id); + } else { + write!(&mut self.buffer, " "); + } + + for _ in 0..self.indent * INDENT { + self.buffer.push(' '); + } + + // Leading dash + self.buffer.write_str("- "); + + // Key and value + self.buffer.write_str(self.temp_key); + if self.temp_val.is_empty() { + self.buffer.push(':'); + } else { + self.buffer.push_str(": "); + self.buffer.push_str(&self.temp_val); + } + self.buffer.push('\n'); + } +} + pub(crate) struct ASTWriter { buffer: String, - temp: String, + temp1: String, + temp2: String, } impl ASTWriter { pub(crate) fn new() -> Self { - Self{ buffer: String::with_capacity(4096), temp: String::with_capacity(256) } + Self{ + buffer: String::with_capacity(4096), + temp1: String::with_capacity(256), + temp2: String::with_capacity(256), + } } pub(crate) fn write_ast(&mut self, w: &mut W, heap: &Heap) { for root_id in heap.protocol_descriptions.iter().map(|v| v.this) { @@ -74,89 +191,73 @@ impl ASTWriter { //-------------------------------------------------------------------------- fn write_module(&mut self, heap: &Heap, root_id: RootId) { - self.write_id_and_indent(PREFIX_ROOT_ID, root_id.0.index, 0); - self.buffer.write_str("Module:\n"); + self.kv(0).with_id(PREFIX_ROOT_ID, root_id.0.index) + .with_s_key("Module"); let root = &heap[root_id]; - - self.write_indent(0); - write!(&mut self.buffer, "- ID: {}\n", root.this.0.index); - - self.write_indent(0); - self.buffer.write_str("- Pragmas:\n"); - + self.kv(1).with_s_key("Pragmas"); for pragma_id in &root.pragmas { - self.write_pragma(&heap[*pragma_id], 1); + self.write_pragma(heap, *pragma_id, 2); } - self.write_indent(0); - self.buffer.write_str("- Imports:\n"); - + self.kv(1).with_s_key("Imports"); for import_id in &root.imports { - self.write_import(&heap[*import_id], 1); + self.write_import(heap, *import_id, 2); } - self.write_indent(0); - self.buffer.write_str("- Definitions:\n"); - - for definition_id in &root.definitions { - self.write_definition(heap, &heap[*definition_id], 1); + self.kv(1).with_s_key("Definitions"); + for def_id in &root.definitions { + self.write_definition(heap, *def_id, 2); } } - fn write_pragma(&mut self, pragma: &Pragma, indent: usize) { - match pragma { + fn write_pragma(&mut self, heap: &Heap, pragma_id: PragmaId, indent: usize) { + match &heap[pragma_id] { Pragma::Version(pragma) => { - self.write_id_and_indent(PREFIX_PRAGMA_ID, pragma.this.0.index, indent); - write!(&mut self.buffer, "- Version: {}\n", pragma.version); + self.kv(indent).with_id(PREFIX_PRAGMA_ID, pragma.this.0.index) + .with_s_key("PragmaVersion") + .with_disp_val(&pragma.version); }, Pragma::Module(pragma) => { - self.write_id_and_indent(PREFIX_PRAGMA_ID, pragma.this.0.index, indent); - write!(&mut self.buffer, "- Module: {}\n", String::from_utf8_lossy(&pragma.value)); + self.kv(indent).with_id(PREFIX_PRAGMA_ID, pragma.this.0.index) + .with_s_key("PragmaModule") + .with_ascii_val(&pragma.value); } } } - fn write_import(&mut self, import: &Import, indent: usize) { + fn write_import(&mut self, heap: &Heap, import_id: ImportId, indent: usize) { + let import = &heap[import_id]; let indent2 = indent + 1; + match import { Import::Module(import) => { - self.write_id_and_indent(PREFIX_IMPORT_ID, import.this.0.index, indent); - write!(&mut self.buffer, "- ModuleImport:\n"); - - self.write_indent(indent2); - write!(&mut self.buffer, "- Name: {}\n", String::from_utf8_lossy(&import.module_name)); - self.write_indent(indent2); - write!(&mut self.buffer, "- Alias: {}\n", String::from_utf8_lossy(&import.alias)); - self.write_indent(indent2); - write_option(&mut self.temp, import.module_id.map(|v| v.0.index)); - write!(&mut self.buffer, "- Target: {}\n", &self.temp); + self.kv(indent).with_id(PREFIX_IMPORT_ID, import.this.0.index) + .with_s_key("ImportModule"); + + self.kv(indent2).with_s_key("Name").with_ascii_val(&import.module_name); + self.kv(indent2).with_s_key("Alias").with_ascii_val(&import.alias); + self.kv(indent2).with_s_key("Target") + .with_opt_disp_val(import.module_id.as_ref().map(|v| &v.0.index)); }, Import::Symbols(import) => { - self.write_id_and_indent(PREFIX_IMPORT_ID, import.this.0.index, indent); - write!(&mut self.buffer, "- SymbolImport:\n"); + self.kv(indent).with_id(PREFIX_IMPORT_ID, import.this.0.index) + .with_s_key("ImportSymbol"); - self.write_indent(indent2); - write!(&mut self.buffer, "- Name: {}\n", String::from_utf8_lossy(&import.module_name)); - self.write_indent(indent2); - write_option(&mut self.temp, import.module_id.map(|v| v.0.index)); - write!(&mut self.buffer, "- Target: {}\n", &self.temp); + self.kv(indent2).with_s_key("Name").with_ascii_val(&import.module_name); + self.kv(indent2).with_s_key("Target") + .with_opt_disp_val(import.module_id.as_ref().map(|v| &v.0.index)); - self.write_indent(indent2); - write!(&mut self.buffer, "- Symbols:\n"); + self.kv(indent2).with_s_key("Symbols"); let indent3 = indent2 + 1; let indent4 = indent3 + 1; for symbol in &import.symbols { - self.write_indent(indent3); - write!(&mut self.buffer, "- AliasedSymbol:\n"); - self.write_indent(indent4); - write!(&mut self.buffer, "- Name: {}\n", String::from_utf8_lossy(&symbol.name)); - self.write_indent(indent4); - write!(&mut self.buffer, "- Alias: {}\n", String::from_utf8_lossy(&symbol.alias)); - self.write_indent(indent4); - write_option(&mut self.temp, symbol.definition_id.map(|v| v.0.index)); - write!(&mut self.buffer, "- Definition: {}\n", &self.temp); + self.kv(indent3).with_s_key("AliasedSymbol"); + self.kv(indent4).with_s_key("Name").with_ascii_val(&symbol.name); + self.kv(indent4).with_s_key("Alias").with_ascii_val(&symbol.alias); + self.kv(indent4).with_s_key("Definition") + .with_opt_disp_val(symbol.definition_id.as_ref().map(|v| &v.0.index)); } } } @@ -166,41 +267,33 @@ impl ASTWriter { // Top-level definition writing //-------------------------------------------------------------------------- - fn write_definition(&mut self, heap: &Heap, def: &Definition, indent: usize) { - match def { + fn write_definition(&mut self, heap: &Heap, def_id: DefinitionId, indent: usize) { + let indent2 = indent + 1; + let indent3 = indent2 + 1; + let indent4 = indent3 + 1; + + match &heap[def_id] { Definition::Struct(_) => todo!("implement Definition::Struct"), Definition::Enum(_) => todo!("implement Definition::Enum"), Definition::Function(_) => todo!("implement Definition::Function"), Definition::Component(def) => { - self.write_id_and_indent(PREFIX_COMPONENT_ID, def.this.0.0.index, indent); - write!(&mut self.buffer, "- Component:\n"); + self.kv(indent).with_id(PREFIX_COMPONENT_ID,def.this.0.0.index) + .with_s_key("DefinitionComponent"); - let indent2 = indent + 1; - let indent3 = indent2 + 1; - let indent4 = indent3 + 1; - self.write_indent(indent2); - write!(&mut self.buffer, "- Name: {}\n", String::from_utf8_lossy(&def.identifier.value)); - self.write_indent(indent2); - write!(&mut self.buffer, "- Variant: {:?}\n", &def.variant); - self.write_indent(indent2); - write!(&mut self.buffer, "- Parameters:\n"); - - for parameter_id in &def.parameters { - let param = &heap[*parameter_id]; - self.write_indent(indent3); - write!(&mut self.buffer, "- Parameter\n"); - - self.write_indent(indent4); - write!(&mut self.buffer, "- Name: {}\n", String::from_utf8_lossy(¶m.identifier.value)); - self.write_indent(indent4); - write!(&mut self.buffer, "- Type: "); - write_type(&mut self.buffer, &heap[param.type_annotation]); - self.buffer.push('\n'); - } + self.kv(indent2).with_s_key("Name").with_ascii_val(&def.identifier.value); + self.kv(indent2).with_s_key("Variant").with_debug_val(&def.variant); - self.write_indent(indent2); - write!(&mut self.buffer, "- Body:\n"); + self.kv(indent2).with_s_key("Parameters"); + for param_id in &def.parameters { + let param = &heap[*param_id]; + self.kv(indent3).with_id(PREFIX_PARAMETER_ID, param_id.0.0.index) + .with_s_key("Parameter"); + self.kv(indent4).with_s_key("Name").with_ascii_val(¶m.identifier.value); + self.kv(indent4).with_s_key("Type").with_custom_val(|w| write_type(w, &heap[param.type_annotation])); + } + + self.kv(indent2).with_s_key("Body"); self.write_stmt(heap, def.body, indent3); } } @@ -208,112 +301,328 @@ impl ASTWriter { fn write_stmt(&mut self, heap: &Heap, stmt_id: StatementId, indent: usize) { let stmt = &heap[stmt_id]; + let indent2 = indent + 1; + let indent3 = indent2 + 1; match stmt { Statement::Block(stmt) => { - self.write_id_and_indent(PREFIX_BLOCK_STMT_ID, stmt.this.0.0.index, indent); - write!(&mut self.buffer, "- Block:\n"); + self.kv(indent).with_id(PREFIX_BLOCK_STMT_ID, stmt.this.0.0.index) + .with_s_key("Block"); + for stmt_id in &stmt.statements { - self.write_stmt(heap, *stmt_id, indent + 1); + self.write_stmt(heap, *stmt_id, indent2); } }, Statement::Local(stmt) => { match stmt { LocalStatement::Channel(stmt) => { - self.write_id_and_indent(PREFIX_CHANNEL_STMT_ID, stmt.this.0.0.0.index, indent); - write!(&mut self.buffer, "- Channel:\n"); - - let indent2 = indent + 1; - let indent3 = indent2 + 1; - let from = &heap[stmt.from]; - self.write_id_and_indent(PREFIX_LOCAL_ID, stmt.from.0.0.index, indent2); + self.kv(indent).with_id(PREFIX_CHANNEL_STMT_ID, stmt.this.0.0.0.index) + .with_s_key("LocalChannel"); + + self.kv(indent2).with_s_key("From"); + self.write_local(heap, stmt.from, indent3); + self.kv(indent2).with_s_key("To"); + self.write_local(heap, stmt.to, indent3); + self.kv(indent2).with_s_key("Next") + .with_opt_disp_val(stmt.next.as_ref().map(|v| &v.0.index)); }, LocalStatement::Memory(stmt) => { - + self.kv(indent).with_id(PREFIX_MEM_STMT_ID, stmt.this.0.0.0.index) + .with_s_key("LocalMemory"); + + self.kv(indent2).with_s_key("Variable"); + self.write_local(heap, stmt.variable, indent3); + self.kv(indent2).with_s_key("initial"); + self.write_expr(heap, stmt.initial, indent3); + self.kv(indent2).with_s_key("Next") + .with_opt_disp_val(stmt.next.as_ref().map(|v| &v.0.index)); } } }, Statement::Skip(stmt) => { - self.write_id_and_indent(PREFIX_SKIP_STMT_ID, stmt.this.0.0.index, indent); - write!(&mut self.buffer, "- Skip\n"); + self.kv(indent).with_id(PREFIX_SKIP_STMT_ID, stmt.this.0.0.index) + .with_s_key("Skip"); + self.kv(indent2).with_s_key("Next") + .with_opt_disp_val(stmt.next.as_ref().map(|v| &v.0.index)); }, Statement::Labeled(stmt) => { - self.write_id_and_indent(PREFIX_LABELED_STMT_ID, stmt.this.0.0.index, indent); - write!(&mut self.buffer, "- LabeledStatement\n"); - - let indent1 = indent + 1; - let indent2 = indent + 2; - self.write_indent(indent1); - write!(&mut self.buffer, "- Label: {}\n", String::from_utf8_lossy(&stmt.label.value)); - self.write_indent(indent1); - write!(&mut self.buffer, "- Statement:\n"); - self.write_stmt(heap, stmt.body, indent2); + self.kv(indent).with_id(PREFIX_LABELED_STMT_ID, stmt.this.0.0.index) + .with_s_key("Labeled"); + + self.kv(indent2).with_s_key("Label").with_ascii_val(&stmt.label.value); + self.kv(indent2).with_s_key("Statement"); + self.write_stmt(heap, stmt.body, indent3); }, Statement::If(stmt) => { + self.kv(indent).with_id(PREFIX_IF_STMT_ID, stmt.this.0.0.index) + .with_s_key("If"); + + self.kv(indent2).with_s_key("EndIf") + .with_opt_disp_val(stmt.end_if.as_ref().map(|v| &v.0.0.index)); + self.kv(indent2).with_s_key("Condition"); + self.write_expr(heap, stmt.test, indent3); + + self.kv(indent2).with_s_key("TrueBody"); + self.write_stmt(heap, stmt.true_body, indent3); + + self.kv(indent2).with_s_key("FalseBody"); + self.write_stmt(heap, stmt.false_body, indent3); }, Statement::EndIf(stmt) => { - + self.kv(indent).with_id(PREFIX_ENDIF_STMT_ID, stmt.this.0.0.index) + .with_s_key("EndIf"); + self.kv(indent2).with_s_key("StartIf").with_disp_val(&stmt.start_if.0.0.index); + self.kv(indent2).with_s_key("Next") + .with_opt_disp_val(stmt.next.as_ref().map(|v| &v.0.index)); }, Statement::While(stmt) => { - + self.kv(indent).with_id(PREFIX_WHILE_STMT_ID, stmt.this.0.0.index) + .with_s_key("While"); + + self.kv(indent2).with_s_key("EndWhile") + .with_opt_disp_val(stmt.end_while.as_ref().map(|v| &v.0.0.index)); + self.kv(indent2).with_s_key("InSync") + .with_opt_disp_val(stmt.in_sync.as_ref().map(|v| &v.0.0.index)); + self.kv(indent2).with_s_key("Condition"); + self.write_expr(heap, stmt.test, indent3); + self.kv(indent2).with_s_key("Body"); + self.write_stmt(heap, stmt.body, indent3); }, Statement::EndWhile(stmt) => { - + self.kv(indent).with_id(PREFIX_ENDWHILE_STMT_ID, stmt.this.0.0.index) + .with_s_key("EndWhile"); + self.kv(indent2).with_s_key("StartWhile").with_disp_val(&stmt.start_while.0.0.index); + self.kv(indent2).with_s_key("Next") + .with_opt_disp_val(stmt.next.as_ref().map(|v| &v.0.index)); }, Statement::Break(stmt) => { - + self.kv(indent).with_id(PREFIX_BREAK_STMT_ID, stmt.this.0.0.index) + .with_s_key("Break"); + self.kv(indent2).with_s_key("Label") + .with_opt_ascii_val(stmt.label.as_ref().map(|v| v.value.as_slice())); + self.kv(indent2).with_s_key("Target") + .with_opt_disp_val(stmt.target.as_ref().map(|v| &v.0.0.index)); }, Statement::Continue(stmt) => { - + self.kv(indent).with_id(PREFIX_CONTINUE_STMT_ID, stmt.this.0.0.index) + .with_s_key("Continue"); + self.kv(indent2).with_s_key("Label") + .with_opt_ascii_val(stmt.label.as_ref().map(|v| v.value.as_slice())); + self.kv(indent2).with_s_key("Target") + .with_opt_disp_val(stmt.target.as_ref().map(|v| &v.0.0.index)); }, Statement::Synchronous(stmt) => { - + self.kv(indent).with_id(PREFIX_SYNC_STMT_ID, stmt.this.0.0.index) + .with_s_key("Synchronous"); + self.kv(indent2).with_s_key("EndSync") + .with_opt_disp_val(stmt.end_sync.as_ref().map(|v| &v.0.0.index)); + self.kv(indent2).with_s_key("Body"); + self.write_stmt(heap, stmt.body, indent3); }, Statement::EndSynchronous(stmt) => { - + self.kv(indent).with_id(PREFIX_ENDSYNC_STMT_ID, stmt.this.0.0.index) + .with_s_key("EndSynchronous"); + self.kv(indent2).with_s_key("StartSync").with_disp_val(&stmt.start_sync.0.0.index); + self.kv(indent2).with_s_key("Next") + .with_opt_disp_val(stmt.next.as_ref().map(|v| &v.0.index)); }, Statement::Return(stmt) => { - + self.kv(indent).with_id(PREFIX_RETURN_STMT_ID, stmt.this.0.0.index) + .with_s_key("Return"); + self.kv(indent2).with_s_key("Expression"); + self.write_expr(heap, stmt.expression, indent3); }, Statement::Assert(stmt) => { - + self.kv(indent).with_id(PREFIX_ASSERT_STMT_ID, stmt.this.0.0.index) + .with_s_key("Assert"); + self.kv(indent2).with_s_key("Expression"); + self.write_expr(heap, stmt.expression, indent3); + self.kv(indent2).with_s_key("Next") + .with_opt_disp_val(stmt.next.as_ref().map(|v| &v.0.index)); }, Statement::Goto(stmt) => { - + self.kv(indent).with_id(PREFIX_GOTO_STMT_ID, stmt.this.0.0.index) + .with_s_key("Goto"); + self.kv(indent2).with_s_key("Label").with_ascii_val(&stmt.label.value); + self.kv(indent2).with_s_key("Target") + .with_opt_disp_val(stmt.target.as_ref().map(|v| &v.0.0.index)); }, Statement::New(stmt) => { - + self.kv(indent).with_id(PREFIX_NEW_STMT_ID, stmt.this.0.0.index) + .with_s_key("New"); + self.kv(indent2).with_s_key("Expression"); + self.write_expr(heap, stmt.expression.upcast(), indent3); + self.kv(indent2).with_s_key("Next") + .with_opt_disp_val(stmt.next.as_ref().map(|v| &v.0.index)); }, Statement::Put(stmt) => { - + self.kv(indent).with_id(PREFIX_PUT_STMT_ID, stmt.this.0.0.index) + .with_s_key("Put"); + self.kv(indent2).with_s_key("Port"); + self.write_expr(heap, stmt.port, indent3); + self.kv(indent2).with_s_key("Message"); + self.write_expr(heap, stmt.message, indent3); + self.kv(indent2).with_s_key("Next") + .with_opt_disp_val(stmt.next.as_ref().map(|v| &v.0.index)); }, Statement::Expression(stmt) => { + self.kv(indent).with_id(PREFIX_EXPR_STMT_ID, stmt.this.0.0.index) + .with_s_key("ExpressionStatement"); + self.write_expr(heap, stmt.expression, indent2); + self.kv(indent2).with_s_key("Next") + .with_opt_disp_val(stmt.next.as_ref().map(|v| &v.0.index)); + } + } + } + fn write_expr(&mut self, heap: &Heap, expr_id: ExpressionId, indent: usize) { + let expr = &heap[expr_id]; + let indent2 = indent + 1; + let indent3 = indent2 + 1; + + match expr { + Expression::Assignment(expr) => { + self.kv(indent).with_id(PREFIX_ASSIGNMENT_EXPR_ID, expr.this.0.0.index) + .with_s_key("AssignmentExpr"); + self.kv(indent2).with_s_key("Operation").with_debug_val(&expr.operation); + self.kv(indent2).with_s_key("Left"); + self.write_expr(heap, expr.left, indent3); + self.kv(indent2).with_s_key("Right"); + self.write_expr(heap, expr.right, indent3); + }, + Expression::Conditional(expr) => { + self.kv(indent).with_id(PREFIX_CONDITIONAL_EXPR_ID, expr.this.0.0.index) + .with_s_key("ConditionalExpr"); + self.kv(indent2).with_s_key("Condition"); + self.write_expr(heap, expr.test, indent3); + self.kv(indent2).with_s_key("TrueExpression"); + self.write_expr(heap, expr.true_expression, indent3); + self.kv(indent2).with_s_key("FalseExpression"); + self.write_expr(heap, expr.false_expression, indent3); + }, + Expression::Binary(expr) => { + self.kv(indent).with_id(PREFIX_BINARY_EXPR_ID, expr.this.0.0.index) + .with_s_key("BinaryExpr"); + self.kv(indent2).with_s_key("Operation").with_debug_val(&expr.operation); + self.kv(indent2).with_s_key("Left"); + self.write_expr(heap, expr.left, indent3); + self.kv(indent2).with_s_key("Right"); + self.write_expr(heap, expr.right, indent3); + }, + Expression::Unary(expr) => { + self.kv(indent).with_id(PREFIX_UNARY_EXPR_ID, expr.this.0.0.index) + .with_s_key("UnaryExpr"); + self.kv(indent2).with_s_key("Operation").with_debug_val(&expr.operation); + self.kv(indent2).with_s_key("Argument"); + self.write_expr(heap, expr.expression, indent3); + }, + Expression::Indexing(expr) => { + self.kv(indent).with_id(PREFIX_INDEXING_EXPR_ID, expr.this.0.0.index) + .with_s_key("IndexingExpr"); + self.kv(indent2).with_s_key("Subject"); + self.write_expr(heap, expr.subject, indent3); + self.kv(indent2).with_s_key("Index"); + self.write_expr(heap, expr.index, indent3); + }, + Expression::Slicing(expr) => { + self.kv(indent).with_id(PREFIX_SLICING_EXPR_ID, expr.this.0.0.index) + .with_s_key("SlicingExpr"); + self.kv(indent2).with_s_key("Subject"); + self.write_expr(heap, expr.subject, indent3); + self.kv(indent2).with_s_key("FromIndex"); + self.write_expr(heap, expr.from_index, indent3); + self.kv(indent2).with_s_key("ToIndex"); + self.write_expr(heap, expr.to_index, indent3); + }, + Expression::Select(expr) => { + self.kv(indent).with_id(PREFIX_SELECT_EXPR_ID, expr.this.0.0.index) + .with_s_key("SelectExpr"); + self.kv(indent2).with_s_key("Subject"); + self.write_expr(heap, expr.subject, indent3); + + match &expr.field { + Field::Length => { + self.kv(indent2).with_s_key("Field").with_s_val("length"); + }, + Field::Symbolic(field) => { + self.kv(indent2).with_s_key("Field").with_ascii_val(&field.value); + } + } + }, + Expression::Array(expr) => { + self.kv(indent).with_id(PREFIX_ARRAY_EXPR_ID, expr.this.0.0.index) + .with_s_key("ArrayExpr"); + self.kv(indent2).with_s_key("Elements"); + for expr_id in &expr.elements { + self.write_expr(heap, *expr_id, indent3); + } + }, + Expression::Constant(expr) => { + self.kv(indent).with_id(PREFIX_CONST_EXPR_ID, expr.this.0.0.index) + .with_s_key("ConstantExpr"); + + let val = self.kv(indent2).with_s_key("Value"); + match &expr.value { + Constant::Null => { val.with_s_val("null"); }, + Constant::True => { val.with_s_val("true"); }, + Constant::False => { val.with_s_val("false"); }, + Constant::Character(char) => { val.with_ascii_val(char); }, + Constant::Integer(int) => { val.with_disp_val(int); }, + } + }, + Expression::Call(expr) => { + self.kv(indent).with_id(PREFIX_CALL_EXPR_ID, expr.this.0.0.index) + .with_s_key("CallExpr"); + + // Method + let method = self.kv(indent2).with_s_key("Method"); + match &expr.method { + Method::Get => { method.with_s_val("get"); }, + Method::Fires => { method.with_s_val("fires"); }, + Method::Create => { method.with_s_val("create"); }, + Method::Symbolic(symbolic) => { + method.with_s_val("symbolic"); + self.kv(indent3).with_s_key("Name").with_ascii_val(&symbolic.identifier.value); + self.kv(indent3).with_s_key("Definition") + .with_opt_disp_val(symbolic.definition.as_ref().map(|v| &v.0.index)); + } + } + + // Arguments + self.kv(indent2).with_s_key("Arguments"); + for arg_id in &expr.arguments { + self.write_expr(heap, *arg_id, indent3); + } + }, + Expression::Variable(expr) => { + self.kv(indent).with_id(PREFIX_VARIABLE_EXPR_ID, expr.this.0.0.index) + .with_s_key("VariableExpr"); + self.kv(indent2).with_s_key("Name").with_ascii_val(&expr.identifier.value); + self.kv(indent2).with_s_key("Definition") + .with_opt_disp_val(expr.declaration.as_ref().map(|v| &v.0.index)); } } } fn write_local(&mut self, heap: &Heap, local_id: LocalId, indent: usize) { - o + let local = &heap[local_id]; + let indent2 = indent + 1; + + self.kv(indent).with_id(PREFIX_LOCAL_ID, local_id.0.0.index) + .with_s_key("Local"); + + self.kv(indent2).with_s_key("Name").with_ascii_val(&local.identifier.value); + self.kv(indent2).with_s_key("Type") + .with_custom_val(|w| write_type(w, &heap[local.type_annotation])); } //-------------------------------------------------------------------------- // Printing Utilities //-------------------------------------------------------------------------- - fn write_id_and_indent(&mut self, prefix: &'static str, id: u32, indent: usize) { - write!(&mut self.buffer, "{}[{:04}] ", prefix, id); - for _ in 0..indent*INDENT { - self.buffer.push(' '); - } - } - - fn write_indent(&mut self, indent: usize) { - write!(&mut self.buffer, "{} ", PREFIX_EMPTY); - for _ in 0..indent*INDENT { - self.buffer.push(' '); - } + fn kv(&mut self, indent: usize) -> KV { + KV::new(&mut self.buffer, &mut self.temp1, &mut self.temp2, indent) } fn flush(&mut self, w: &mut W) { @@ -343,7 +652,7 @@ fn write_type(target: &mut String, t: &TypeAnnotation) { PrimitiveType::Symbolic(symbolic) => { let mut temp = String::new(); write_option(&mut temp, symbolic.definition.map(|v| v.0.index)); - write!(target, "Symbolic(name: {}, target: {})", String::from_utf8_lossy(&symbolic.identifier.value), &temp); + write!(target, "Symbolic(name: {}, target: {})", String::from_utf8_lossy(&symbolic.identifier.value), &temp) } }; diff --git a/src/protocol/eval.rs b/src/protocol/eval.rs index 6c7de0873cbf2cdb68d8bb9afad60a9bc439a86b..60534eb7e08209072928c3d672a4c2c3c4c8bf61 100644 --- a/src/protocol/eval.rs +++ b/src/protocol/eval.rs @@ -1640,6 +1640,7 @@ impl Prompt { if self.position.is_none() { return Err(EvalContinuation::Terminal); } + let stmt = &h[self.position.unwrap()]; match stmt { Statement::Block(stmt) => { diff --git a/src/protocol/lexer.rs b/src/protocol/lexer.rs index d028334b8af496dfe91ed4cbf055a97e99c70542..00407f726ef22a859e6df437db94fe793f7243f3 100644 --- a/src/protocol/lexer.rs +++ b/src/protocol/lexer.rs @@ -382,6 +382,7 @@ impl Lexer<'_> { self.consume_keyword(b"long")?; Ok(PrimitiveType::Long) } else if self.has_keyword(b"let") { + // TODO: @types return Err(self.error_at_pos("inferred types using 'let' are reserved, but not yet implemented")); } else { let identifier = self.consume_namespaced_identifier()?; @@ -1196,12 +1197,20 @@ impl Lexer<'_> { // Statements // ==================== - fn consume_statement(&mut self, h: &mut Heap) -> Result { + /// Consumes any kind of statement from the source and will error if it + /// did not encounter a statement. Will also return an error if the + /// statement is nested too deeply. + /// + /// `wrap_in_block` may be set to true to ensure that the parsed statement + /// will be wrapped in a block statement if it is not already a block + /// statement. This is used to ensure that all `if`, `while` and `sync` + /// statements have a block statement as body. + fn consume_statement(&mut self, h: &mut Heap, wrap_in_block: bool) -> Result { if self.level >= MAX_LEVEL { return Err(self.error_at_pos("Too deeply nested statement")); } self.level += 1; - let result = self.consume_statement_impl(h); + let result = self.consume_statement_impl(h, wrap_in_block); self.level -= 1; result } @@ -1223,36 +1232,58 @@ impl Lexer<'_> { self.source.seek(backup_pos); return result; } - fn consume_statement_impl(&mut self, h: &mut Heap) -> Result { - if self.has_string(b"{") { - Ok(self.consume_block_statement(h)?) + fn consume_statement_impl(&mut self, h: &mut Heap, wrap_in_block: bool) -> Result { + // Parse and allocate statement + let mut must_wrap = true; + let mut stmt_id = if self.has_string(b"{") { + must_wrap = false; + self.consume_block_statement(h)? } else if self.has_keyword(b"skip") { - Ok(self.consume_skip_statement(h)?.upcast()) + must_wrap = false; + self.consume_skip_statement(h)?.upcast() } else if self.has_keyword(b"if") { - Ok(self.consume_if_statement(h)?.upcast()) + self.consume_if_statement(h)?.upcast() } else if self.has_keyword(b"while") { - Ok(self.consume_while_statement(h)?.upcast()) + self.consume_while_statement(h)?.upcast() } else if self.has_keyword(b"break") { - Ok(self.consume_break_statement(h)?.upcast()) + self.consume_break_statement(h)?.upcast() } else if self.has_keyword(b"continue") { - Ok(self.consume_continue_statement(h)?.upcast()) + self.consume_continue_statement(h)?.upcast() } else if self.has_keyword(b"synchronous") { - Ok(self.consume_synchronous_statement(h)?.upcast()) + self.consume_synchronous_statement(h)?.upcast() } else if self.has_keyword(b"return") { - Ok(self.consume_return_statement(h)?.upcast()) + self.consume_return_statement(h)?.upcast() } else if self.has_keyword(b"assert") { - Ok(self.consume_assert_statement(h)?.upcast()) + self.consume_assert_statement(h)?.upcast() } else if self.has_keyword(b"goto") { - Ok(self.consume_goto_statement(h)?.upcast()) + self.consume_goto_statement(h)?.upcast() } else if self.has_keyword(b"new") { - Ok(self.consume_new_statement(h)?.upcast()) + self.consume_new_statement(h)?.upcast() } else if self.has_keyword(b"put") { - Ok(self.consume_put_statement(h)?.upcast()) + self.consume_put_statement(h)?.upcast() } else if self.has_label() { - Ok(self.consume_labeled_statement(h)?.upcast()) + self.consume_labeled_statement(h)?.upcast() } else { - Ok(self.consume_expression_statement(h)?.upcast()) + self.consume_expression_statement(h)?.upcast() + }; + + // Wrap if desired and if needed + if must_wrap && wrap_in_block { + let position = h[stmt_id].position(); + let block_wrapper = h.alloc_block_statement(|this| BlockStatement{ + this, + position, + statements: vec![stmt_id], + parent_scope: None, + relative_pos_in_parent: 0, + locals: Vec::new(), + labels: Vec::new() + }); + + stmt_id = block_wrapper.upcast(); } + + Ok(stmt_id) } fn has_local_statement(&mut self) -> bool { /* To avoid ambiguity, we look ahead to find either the @@ -1289,7 +1320,7 @@ impl Lexer<'_> { self.consume_whitespace(false)?; } while !self.has_string(b"}") { - statements.push(self.consume_statement(h)?); + statements.push(self.consume_statement(h, false)?); self.consume_whitespace(false)?; } self.consume_string(b"}")?; @@ -1389,7 +1420,7 @@ impl Lexer<'_> { self.consume_whitespace(false)?; self.consume_string(b":")?; self.consume_whitespace(false)?; - let body = self.consume_statement(h)?; + let body = self.consume_statement(h, false)?; Ok(h.alloc_labeled_statement(|this| LabeledStatement { this, position, @@ -1412,12 +1443,12 @@ impl Lexer<'_> { self.consume_whitespace(false)?; let test = self.consume_paren_expression(h)?; self.consume_whitespace(false)?; - let true_body = self.consume_statement(h)?; + let true_body = self.consume_statement(h, true)?; self.consume_whitespace(false)?; let false_body = if self.has_keyword(b"else") { self.consume_keyword(b"else")?; self.consume_whitespace(false)?; - self.consume_statement(h)? + self.consume_statement(h, true)? } else { h.alloc_skip_statement(|this| SkipStatement { this, position, next: None }).upcast() }; @@ -1429,7 +1460,7 @@ impl Lexer<'_> { self.consume_whitespace(false)?; let test = self.consume_paren_expression(h)?; self.consume_whitespace(false)?; - let body = self.consume_statement(h)?; + let body = self.consume_statement(h, true)?; Ok(h.alloc_while_statement(|this| WhileStatement { this, position, @@ -1490,7 +1521,7 @@ impl Lexer<'_> { // } else if !self.has_keyword(b"skip") && !self.has_string(b"{") { // return Err(self.error_at_pos("Expected block statement")); // } - let body = self.consume_statement(h)?; + let body = self.consume_statement(h, true)?; Ok(h.alloc_synchronous_statement(|this| SynchronousStatement { this, position, diff --git a/src/protocol/parser/depth_visitor.rs b/src/protocol/parser/depth_visitor.rs index cacb73667ea698069aad629d4cbce42b7fd6693d..b3792213d2fdb11780d8eafe99aca7284fde1626 100644 --- a/src/protocol/parser/depth_visitor.rs +++ b/src/protocol/parser/depth_visitor.rs @@ -78,9 +78,15 @@ pub(crate) trait Visitor: Sized { fn visit_if_statement(&mut self, h: &mut Heap, stmt: IfStatementId) -> VisitorResult { recursive_if_statement(self, h, stmt) } + fn visit_end_if_statement(&mut self, _h: &mut Heap, _stmt: EndIfStatementId) -> VisitorResult { + Ok(()) + } fn visit_while_statement(&mut self, h: &mut Heap, stmt: WhileStatementId) -> VisitorResult { recursive_while_statement(self, h, stmt) } + fn visit_end_while_statement(&mut self, _h: &mut Heap, _stmt: EndWhileStatementId) -> VisitorResult { + Ok(()) + } fn visit_break_statement(&mut self, _h: &mut Heap, _stmt: BreakStatementId) -> VisitorResult { Ok(()) } @@ -98,6 +104,9 @@ pub(crate) trait Visitor: Sized { ) -> VisitorResult { recursive_synchronous_statement(self, h, stmt) } + fn visit_end_synchronous_statement(&mut self, _h: &mut Heap, _stmt: EndSynchronousStatementId) -> VisitorResult { + Ok(()) + } fn visit_return_statement(&mut self, h: &mut Heap, stmt: ReturnStatementId) -> VisitorResult { recursive_return_statement(self, h, stmt) } @@ -314,10 +323,9 @@ fn recursive_statement(this: &mut T, h: &mut Heap, stmt: StatementId Statement::New(stmt) => this.visit_new_statement(h, stmt.this), Statement::Put(stmt) => this.visit_put_statement(h, stmt.this), Statement::Expression(stmt) => this.visit_expression_statement(h, stmt.this), - Statement::EndSynchronous(_) | Statement::EndWhile(_) | Statement::EndIf(_) => { - // unreachable!() // pseudo-statement - Ok(()) - } + Statement::EndSynchronous(stmt) => this.visit_end_synchronous_statement(h, stmt.this), + Statement::EndWhile(stmt) => this.visit_end_while_statement(h, stmt.this), + Statement::EndIf(stmt) => this.visit_end_if_statement(h, stmt.this), } } @@ -1137,40 +1145,53 @@ impl Visitor for LinkStatements { Ok(()) } fn visit_if_statement(&mut self, h: &mut Heap, stmt: IfStatementId) -> VisitorResult { - // 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, start_if: stmt, position, next: None }).upcast(); + // Link the two branches to the corresponding EndIf pseudo-statement + let end_if_id = h[stmt].end_if; + assert!(end_if_id.is_some()); + let end_if_id = end_if_id.unwrap(); + assert!(self.prev.is_none()); self.visit_statement(h, h[stmt].true_body)?; if let Some(UniqueStatementId(prev)) = self.prev.take() { - h[prev].link_next(pseudo); + h[prev].link_next(end_if_id.upcast()); } + assert!(self.prev.is_none()); self.visit_statement(h, h[stmt].false_body)?; if let Some(UniqueStatementId(prev)) = self.prev.take() { - h[prev].link_next(pseudo); + h[prev].link_next(end_if_id.upcast()); } + // Use the pseudo-statement as the statement where to update the next pointer - self.prev = Some(UniqueStatementId(pseudo)); + // self.prev = Some(UniqueStatementId(end_if_id.upcast())); + Ok(()) + } + fn visit_end_if_statement(&mut self, _h: &mut Heap, stmt: EndIfStatementId) -> VisitorResult { + assert!(self.prev.is_none()); + self.prev = Some(UniqueStatementId(stmt.upcast())); Ok(()) } fn visit_while_statement(&mut self, h: &mut Heap, stmt: WhileStatementId) -> VisitorResult { // 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, start_while: stmt, position, next: None }); // Update the while's next statement to point to the pseudo-statement - h[stmt].end_while = Some(pseudo); + let end_while_id = h[stmt].end_while; + assert!(end_while_id.is_some()); + let end_while_id = end_while_id.unwrap(); + assert!(self.prev.is_none()); self.visit_statement(h, h[stmt].body)?; // The body's next statement loops back to the while statement itself // Note: continue statements also loop back to the while statement itself - if let Some(UniqueStatementId(prev)) = std::mem::replace(&mut self.prev, None) { + if let Some(UniqueStatementId(prev)) = self.prev.take() { h[prev].link_next(stmt.upcast()); } // Use the while statement as the statement where the next pointer is updated - self.prev = Some(UniqueStatementId(pseudo.upcast())); + // self.prev = Some(UniqueStatementId(end_while_id.upcast())); + Ok(()) + } + fn visit_end_while_statement(&mut self, _h: &mut Heap, stmt: EndWhileStatementId) -> VisitorResult { + assert!(self.prev.is_none()); + self.prev = Some(UniqueStatementId(stmt.upcast())); Ok(()) } fn visit_break_statement(&mut self, _h: &mut Heap, _stmt: BreakStatementId) -> VisitorResult { @@ -1191,23 +1212,23 @@ impl Visitor for LinkStatements { // Allocate a pseudo-statement, that is added for helping the evaluator to issue a command // that marks the end of the synchronous block. Every evaluation has to pause at this // point, only to resume later when the thread is selected as unique thread to continue. - let position = h[stmt].position; - let pseudo = h - .alloc_end_synchronous_statement(|this| EndSynchronousStatement { - this, - start_sync: stmt, - position, - next: None, - }) - .upcast(); + let end_sync_id = h[stmt].end_sync; + assert!(end_sync_id.is_some()); + let end_sync_id = end_sync_id.unwrap(); + assert!(self.prev.is_none()); self.visit_statement(h, h[stmt].body)?; // The body's next statement points to the pseudo element - if let Some(UniqueStatementId(prev)) = std::mem::replace(&mut self.prev, None) { - h[prev].link_next(pseudo); + if let Some(UniqueStatementId(prev)) = self.prev.take() { + h[prev].link_next(end_sync_id.upcast()); } // Use the pseudo-statement as the statement where the next pointer is updated - self.prev = Some(UniqueStatementId(pseudo)); + // self.prev = Some(UniqueStatementId(end_sync_id.upcast())); + Ok(()) + } + fn visit_end_synchronous_statement(&mut self, _h: &mut Heap, stmt: EndSynchronousStatementId) -> VisitorResult { + assert!(self.prev.is_none()); + self.prev = Some(UniqueStatementId(stmt.upcast())); Ok(()) } fn visit_return_statement(&mut self, _h: &mut Heap, _stmt: ReturnStatementId) -> VisitorResult { diff --git a/src/protocol/parser/mod.rs b/src/protocol/parser/mod.rs index 844cd3f795a1d968dc7ef501134d448d0a465337..077a32f98012c8fdee825b160b8ca1102fdaf874 100644 --- a/src/protocol/parser/mod.rs +++ b/src/protocol/parser/mod.rs @@ -206,19 +206,16 @@ impl Parser { 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) - } - - 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); + visit.visit_module(&mut ctx)?; 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) } @@ -230,7 +227,7 @@ impl Parser { // 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)?; + // 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)?; diff --git a/src/protocol/parser/shallow_visitor.rs b/src/protocol/parser/shallow_visitor.rs deleted file mode 100644 index f7082890de7f68e8716ffd0f72bb971d020a85d3..0000000000000000000000000000000000000000 --- a/src/protocol/parser/shallow_visitor.rs +++ /dev/null @@ -1,12 +0,0 @@ -use crate::protocol::ast::*; -use crate::protocol::input_source::*; -use crate::protocol::lexer::*; - -type Unit = (); -type VisitorResult = Result; - -trait ShallowVisitor: Sized { - fn visit_protocol_description(&mut self, h: &mut Heap, pd: RootId) -> VisitorResult { - - } -} \ No newline at end of file diff --git a/src/protocol/parser/symbol_table.rs b/src/protocol/parser/symbol_table.rs index 34f390f1ebddd74d95279b272eaee7b7ba5750df..d9b70b2bbb2e6fd06b023fca297ece83aa1cc62e 100644 --- a/src/protocol/parser/symbol_table.rs +++ b/src/protocol/parser/symbol_table.rs @@ -284,20 +284,6 @@ impl SymbolTable { 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, "miscalculated reserved size for symbol lookup table" diff --git a/src/protocol/parser/type_resolver.rs b/src/protocol/parser/type_resolver.rs new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/protocol/parser/type_table.rs b/src/protocol/parser/type_table.rs index ea646b9f65182221bb1be23b15a0a4f1cf645896..1c54fc3dde40c4d9dd7e6009ce1e2b8cd1d39932 100644 --- a/src/protocol/parser/type_table.rs +++ b/src/protocol/parser/type_table.rs @@ -5,7 +5,34 @@ use crate::protocol::inputsource::*; use crate::protocol::parser::*; use std::collections::HashMap; +use crate::common::Formatter; + +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum TypeClass { + Enum, + Union, + Struct, + Function, + Component +} +impl TypeClass { + pub(crate) fn display_name(&self) -> &'static str { + match self { + TypeClass::Enum => "enum", + TypeClass::Union => "enum", + TypeClass::Struct => "struct", + TypeClass::Function => "function", + TypeClass::Component => "component", + } + } +} + +impl std::fmt::Display for TypeClass { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.display_name()) + } +} pub enum DefinedType { Enum(EnumType), @@ -15,6 +42,18 @@ pub enum DefinedType { Component(ComponentType) } +impl DefinedType { + pub(crate) fn type_class(&self) -> TypeClass { + match self { + DefinedType::Enum(_) => TypeClass::Enum, + DefinedType::Union(_) => TypeClass::Union, + DefinedType::Struct(_) => TypeClass::Struct, + DefinedType::Function(_) => TypeClass::Function, + DefinedType::Component(_) => TypeClass::Component + } + } +} + // TODO: Also support maximum u64 value pub struct EnumVariant { identifier: Identifier, diff --git a/src/protocol/parser/visitor.rs b/src/protocol/parser/visitor.rs index b8c169565291bf0b003447df394092a99e4359b8..86aac5fc1b59a89d9000109abe1bcd0a0e5b68ca 100644 --- a/src/protocol/parser/visitor.rs +++ b/src/protocol/parser/visitor.rs @@ -275,9 +275,12 @@ pub(crate) struct ValidityAndLinkerVisitor { // inserted after the breadth-pass relative_pos_in_block: u32, // Single buffer of statement IDs that we want to traverse in a block. - // Required to work around Rust borrowing rules - // TODO: Maybe remove this in the future + // Required to work around Rust borrowing rules and to prevent constant + // cloning of vectors. statement_buffer: Vec, + // Another buffer, now with expression IDs, to prevent constant cloning of + // vectors while working around rust's borrowing rules + expression_buffer: Vec, // Statements to insert after the breadth pass in a single block insert_buffer: Vec<(u32, StatementId)>, } @@ -292,6 +295,7 @@ impl ValidityAndLinkerVisitor { performing_breadth_pass: false, relative_pos_in_block: 0, statement_buffer: Vec::with_capacity(256), + expression_buffer: Vec::with_capacity(256), insert_buffer: Vec::with_capacity(32), } } @@ -595,6 +599,7 @@ impl Visitor2 for ValidityAndLinkerVisitor { } fn visit_new_stmt(&mut self, ctx: &mut Ctx, id: NewStatementId) -> VisitorResult { + // Link the call expression following the new statement if self.performing_breadth_pass { // TODO: Cleanup error messages, can be done cleaner // Make sure new statement occurs within a composite component @@ -610,30 +615,24 @@ impl Visitor2 for ValidityAndLinkerVisitor { let definition_id = { 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") - ) - } + let found_symbol = self.find_symbol_of_type( + ctx.module.root_id, &ctx.symbols, &ctx.types, + &symbolic.identifier, TypeClass::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 found_symbol { + FindOfTypeResult::Found(definition_id) => definition_id, + FindOfTypeResult::TypeMismatch(got_type_class) => { + return Err(ParseError2::new_error( + &ctx.module.source, symbolic.identifier.position, + &format!("New must instantiate a component, this identifier points to a {}", got_type_class) + )) + }, + FindOfTypeResult::NotFound => { + return Err(ParseError2::new_error( + &ctx.module.source, symbolic.identifier.position, + "Could not find a defined component with this name" + )) } } } else { @@ -650,6 +649,23 @@ impl Visitor2 for ValidityAndLinkerVisitor { Method::Symbolic(method) => method.definition = Some(definition_id), _ => unreachable!() } + } else { + // Performing depth pass. The function definition should have been + // resolved in the breadth pass, now we recurse to evaluate the + // arguments + let call_expr_id = ctx.heap[id].expression; + let call_expr = &ctx.heap[call_expr_id]; + + let old_num_exprs = self.expression_buffer.len(); + self.expression_buffer.extend(&call_expr.arguments); + let new_num_exprs = self.expression_buffer.len(); + + for arg_expr_idx in old_num_exprs..new_num_exprs { + let arg_expr_id = self.expression_buffer[arg_expr_idx]; + self.visit_expr(ctx, arg_expr_id)?; + } + + self.expression_buffer.truncate(old_num_exprs); } Ok(()) @@ -692,6 +708,11 @@ impl Visitor2 for ValidityAndLinkerVisitor { fn visit_assignment_expr(&mut self, ctx: &mut Ctx, id: AssignmentExpressionId) -> VisitorResult { debug_assert!(!self.performing_breadth_pass); + let assignment_expr = &ctx.heap[id]; + let left_expr_id = assignment_expr.left; + let right_expr_id = assignment_expr.right; + self.visit_expr(ctx, left_expr_id)?; + self.visit_expr(ctx, right_expr_id)?; Ok(()) } @@ -750,11 +771,6 @@ impl Visitor2 for ValidityAndLinkerVisitor { fn visit_select_expr(&mut self, ctx: &mut Ctx, id: SelectExpressionId) -> VisitorResult { debug_assert!(!self.performing_breadth_pass); - // TODO: Is it true that this always depends on the return value? I - // mean: the following should be a valid expression: - // 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 expr_id = ctx.heap[id].subject; self.visit_expr(ctx, expr_id)?; @@ -764,9 +780,18 @@ 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_expr_id in array_expr.elements.clone() { // TODO: @performance + + let old_num_exprs = self.expression_buffer.len(); + self.expression_buffer.extend(&array_expr.elements); + let new_num_exprs = self.expression_buffer.len(); + + for field_expr_idx in old_num_exprs..new_num_exprs { + let field_expr_id = self.expression_buffer[field_expr_idx]; self.visit_expr(ctx, field_expr_id)?; } + + self.expression_buffer.truncate(old_num_exprs); + Ok(()) } @@ -779,6 +804,9 @@ impl Visitor2 for ValidityAndLinkerVisitor { debug_assert!(!self.performing_breadth_pass); let call_expr = &mut ctx.heap[id]; + + // Resolve the method to the appropriate definition and check the + // legality of the particular method call. match &mut call_expr.method { Method::Create => {}, Method::Fires => { @@ -799,42 +827,43 @@ impl Visitor2 for ValidityAndLinkerVisitor { }, Method::Symbolic(symbolic) => { // Find symbolic method - let symbol = ctx.symbols.resolve_namespaced_symbol(ctx.module.root_id, &symbolic.identifier); - if symbol.is_none() { - return Err(ParseError2::new_error( - &ctx.module.source, symbolic.identifier.position, - "Could not find definition of function call" - )); - } - let (symbol, iter) = symbol.unwrap(); - if iter.num_remaining() != 0 { - return Err( - ParseError2::new_error(&ctx.module.source, symbolic.identifier.position,"Could not find definition of function call") - .with_postfixed_info(&ctx.module.source, symbol.position, "Could resolve part of the identifier to this symbol") - ); - } - let definition_id = match &symbol.symbol { - Symbol::Definition((_, definition_id)) => { - let definition = ctx.types.get_definition(definition_id); - debug_assert!(definition.is_some(), "Symbol resolved to definition, but not present in type table"); - let definition = definition.unwrap(); - match definition { - DefinedType::Function(_) => Some(*definition_id), - _ => None, - } + let found_symbol = self.find_symbol_of_type( + ctx.module.root_id, &ctx.symbols, &ctx.types, + &symbolic.identifier, TypeClass::Function + ); + let definition_id = match found_symbol { + FindOfTypeResult::Found(definition_id) => definition_id, + FindOfTypeResult::TypeMismatch(got_type_class) => { + return Err(ParseError2::new_error( + &ctx.module.source, symbolic.identifier.position, + &format!("Only functions can be called, this identifier points to a {}", got_type_class) + )) }, - Symbol::Namespace(_) => None, + FindOfTypeResult::NotFound => { + return Err(ParseError2::new_error( + &ctx.module.source, symbolic.identifier.position, + &format!("Could not find a function with this name") + )) + } }; - if definition_id.is_none() { - return Err( - ParseError2::new_error(&ctx.module.source, symbolic.identifier.position, "Could not find definition of function call") - ); - } - symbolic.definition = Some(definition_id.unwrap()); + symbolic.definition = Some(definition_id); } } + // Parse all the arguments in the depth pass as well + let call_expr = &mut ctx.heap[id]; + let old_num_exprs = self.expression_buffer.len(); + self.expression_buffer.extend(&call_expr.arguments); + let new_num_exprs = self.expression_buffer.len(); + + for arg_expr_idx in old_num_exprs..new_num_exprs { + let arg_expr_id = self.expression_buffer[arg_expr_idx]; + self.visit_expr(ctx, arg_expr_id)?; + } + + self.expression_buffer.truncate(old_num_exprs); + Ok(()) } @@ -842,7 +871,6 @@ 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); @@ -851,11 +879,23 @@ impl Visitor2 for ValidityAndLinkerVisitor { } } +enum FindOfTypeResult { + // Identifier was exactly matched, type matched as well + Found(DefinitionId), + // Identifier was matched, but the type differs from the expected one + TypeMismatch(&'static str), + // Identifier could not be found + NotFound, +} + impl ValidityAndLinkerVisitor { //-------------------------------------------------------------------------- // Special traversal //-------------------------------------------------------------------------- + /// Will visit a statement with a hint about its wrapping statement. This is + /// used to distinguish block statements with a wrapping synchronous + /// statement from normal block statements. fn visit_stmt_with_hint(&mut self, ctx: &mut Ctx, id: StatementId, hint: Option) -> VisitorResult { if let Statement::Block(block_stmt) = &ctx.heap[id] { let block_id = block_stmt.this; @@ -872,37 +912,41 @@ impl ValidityAndLinkerVisitor { return Ok(()) } + // Set parent scope and relative position in the parent scope. Remember + // these values to set them back to the old values when we're done with + // the traversal of the block's statements. let body = &mut ctx.heap[id]; body.parent_scope = self.cur_scope.clone(); + println!("DEBUG: Assigning relative {} to block {}", self.relative_pos_in_block, id.0.0.index); body.relative_pos_in_parent = self.relative_pos_in_block; - // 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::Synchronous((sync_id, id)), None => Scope::Regular(id), }); - let first_statement_index = self.statement_buffer.len(); + let old_relative_pos = self.relative_pos_in_block; + // Copy statement IDs into buffer + let old_num_stmts = self.statement_buffer.len(); { let body = &ctx.heap[id]; self.statement_buffer.extend_from_slice(&body.statements); } + let new_num_stmts = self.statement_buffer.len(); - let mut stmt_index = first_statement_index; - while stmt_index < self.statement_buffer.len() { - self.relative_pos_in_block = (stmt_index - first_statement_index) as u32; - self.visit_stmt(ctx, self.statement_buffer[stmt_index])?; - stmt_index += 1; + // Perform the breadth-first pass. Its main purpose is to find labeled + // statements such that we can find the `goto`-targets immediately when + // performing the depth pass + self.performing_breadth_pass = true; + for stmt_idx in old_num_stmts..new_num_stmts { + self.relative_pos_in_block = (stmt_idx - old_num_stmts) as u32; + self.visit_stmt(ctx, self.statement_buffer[stmt_idx])?; } if !self.insert_buffer.is_empty() { let body = &mut ctx.heap[id]; - for (pos, stmt) in self.insert_buffer.drain(..) { - body.statements.insert(pos as usize, stmt); + for (insert_idx, (pos, stmt)) in self.insert_buffer.drain(..).enumerate() { + body.statements.insert(pos as usize + insert_idx, stmt); } } @@ -910,18 +954,17 @@ impl ValidityAndLinkerVisitor { // nodes because we're using the statement buffer, we may safely use the // relative_pos_in_block counter. self.performing_breadth_pass = false; - stmt_index = first_statement_index; - while stmt_index < self.statement_buffer.len() { - self.relative_pos_in_block = (stmt_index - first_statement_index) as u32; - self.visit_stmt(ctx, self.statement_buffer[stmt_index])?; - stmt_index += 1; + for stmt_idx in old_num_stmts..new_num_stmts { + self.relative_pos_in_block = (stmt_idx - old_num_stmts) as u32; + self.visit_stmt(ctx, self.statement_buffer[stmt_idx])?; } self.cur_scope = old_scope; + self.relative_pos_in_block = old_relative_pos; // Pop statement buffer debug_assert!(self.insert_buffer.is_empty(), "insert buffer not empty after depth pass"); - self.statement_buffer.truncate(first_statement_index); + self.statement_buffer.truncate(old_num_stmts); Ok(()) } @@ -1018,11 +1061,15 @@ impl ValidityAndLinkerVisitor { // identifier in the namespace. // No need to use iterator over namespaces if here let mut scope = self.cur_scope.as_ref().unwrap(); + println!(" *** DEBUG: Looking for {}, depth = {}", String::from_utf8_lossy(&identifier.value), self.performing_breadth_pass); loop { debug_assert!(scope.is_block()); let block = &ctx.heap[scope.to_block()]; + println!("DEBUG: Looking in block {} with relative pos {}", block.this.0.0.index, relative_pos); for local_id in &block.locals { let local = &ctx.heap[*local_id]; + println!("DEBUG: Comparing against '{}' with relative pos {}", + String::from_utf8_lossy(&local.identifier.value), local.relative_pos_in_block); if local.relative_pos_in_block < relative_pos && local.identifier.value == identifier.value { return Ok(local_id.upcast()); } @@ -1032,6 +1079,7 @@ impl ValidityAndLinkerVisitor { scope = block.parent_scope.as_ref().unwrap(); if !scope.is_block() { // Definition scope, need to check arguments to definition + println!("DEBUG: Looking in definition scope now..."); match scope { Scope::Definition(definition_id) => { let definition = &ctx.heap[*definition_id]; @@ -1055,6 +1103,8 @@ impl ValidityAndLinkerVisitor { } } + /// Adds a particular label to the current scope. Will return an error if + /// there is another label with the same name visible in the current scope. fn checked_label_add(&mut self, ctx: &mut Ctx, id: LabeledStatementId) -> Result<(), ParseError2> { debug_assert!(self.cur_scope.is_some()); @@ -1133,6 +1183,38 @@ impl ValidityAndLinkerVisitor { } } + /// Finds a particular symbol in the symbol table which must correspond to + /// a definition of a particular type. + // Note: root_id, symbols and types passed in explicitly to prevent + // borrowing errors + fn find_symbol_of_type( + &self, root_id: RootId, symbols: &SymbolTable, types: &TypeTable, + identifier: &NamespacedIdentifier, expected_type_class: TypeClass + ) -> FindOfTypeResult { + // Find symbol associated with identifier + let symbol = symbols.resolve_namespaced_symbol(root_id, &identifier); + if symbol.is_none() { return FindOfTypeResult::NotFound; } + + let (symbol, iter) = symbol.unwrap(); + if iter.num_remaining() != 0 { return FindOfTypeResult::NotFound; } + + match &symbol.symbol { + Symbol::Definition((_, definition_id)) => { + // Make sure definition is of the expected type + let definition_type = types.get_definition(definition_id); + debug_assert!(definition_type.is_some(), "Found symbol '{}' in symbol table, but not in type table", String::from_utf8_lossy(&identifier.value)); + let definition_type_class = definition_type.unwrap().type_class(); + + if definition_type_class != expected_type_class { + FindOfTypeResult::TypeMismatch(definition_type_class.display_name()) + } else { + FindOfTypeResult::Found(*definition_id) + } + }, + Symbol::Namespace(_) => FindOfTypeResult::TypeMismatch("namespace"), + } + } + /// This function will check if the provided while statement ID has a block /// statement that is one of our current parents. fn has_parent_while_scope(&self, ctx: &Ctx, id: WhileStatementId) -> bool { diff --git a/src/runtime/tests.rs b/src/runtime/tests.rs index ae32b8c4e0008ad3255cb2b07642dbbe6237b64c..03eba43af3465abf484aeede0228df3a8889bd45 100644 --- a/src/runtime/tests.rs +++ b/src/runtime/tests.rs @@ -1397,6 +1397,20 @@ fn eq_no_causality() { } } } + primitive quick_test(in a, in b) { + msg ma = null; + while(true) synchronous { + if (fires(a)) { + ma = get(a); + } + if (fires(b)) { + ma = get(b); + } + if (fires(a) && fires(b)) { + ma = get(a) + get(b); + } + } + } "; let pd = reowolf::ProtocolDescription::parse(pdl).unwrap(); let mut c = file_logged_configured_connector(0, test_log_path, Arc::new(pd));