From 87aa65714efe1e8318c42ca47a5624e6d4643f80 2021-05-04 11:13:24 From: MH Date: 2021-05-04 11:13:24 Subject: [PATCH] back to a compiling project --- diff --git a/src/collections/scoped_buffer.rs b/src/collections/scoped_buffer.rs index 051d3618ffa00d6874b4c1cf353a5f6140ed53ea..a699e66b62879a0e91d57593deb425a243379b2c 100644 --- a/src/collections/scoped_buffer.rs +++ b/src/collections/scoped_buffer.rs @@ -1,3 +1,5 @@ +use std::iter::FromIterator; + /// scoped_buffer.rs /// /// Solves the common pattern where we are performing some kind of recursive @@ -8,37 +10,35 @@ /// It is unsafe because we're using pointers to circumvent borrowing rules in /// the name of code cleanliness. The correctness of use is checked in debug /// mode. - -/// The buffer itself. This struct should be the shared buffer. The type `T` is -/// intentionally `Copy` such that it can be copied out and the underlying -/// container can be truncated. -pub(crate) struct ScopedBuffer { +pub(crate) struct ScopedBuffer { pub inner: Vec, } /// A section of the buffer. Keeps track of where we started the section. When /// done with the section one must call `into_vec` or `forget` to remove the /// section from the underlying buffer. -pub(crate) struct ScopedSection { +pub(crate) struct ScopedSection { inner: *mut Vec, start_size: u32, #[cfg(debug_assertions)] cur_size: u32, } -impl ScopedBuffer { +impl ScopedBuffer { pub(crate) fn new_reserved(capacity: usize) -> Self { - Self{ inner: Vec::with_capacity(capacity) } + Self { inner: Vec::with_capacity(capacity) } } pub(crate) fn start_section(&mut self) -> ScopedSection { let start_size = self.inner.len() as u32; - ScopedSection{ + ScopedSection { inner: &mut self.inner, start_size, cur_size: start_size } } +} +impl ScopedBuffer { pub(crate) fn start_section_initialized(&mut self, initialize_with: &[T]) -> ScopedSection { let start_size = self.inner.len() as u32; let data_size = initialize_with.len() as u32; @@ -52,14 +52,14 @@ impl ScopedBuffer { } #[cfg(debug_assertions)] -impl Drop for ScopedBuffer { +impl Drop for ScopedBuffer { fn drop(&mut self) { // Make sure that everyone cleaned up the buffer neatly debug_assert!(self.inner.is_empty(), "dropped non-empty scoped buffer"); } } -impl ScopedSection { +impl ScopedSection { #[inline] pub(crate) fn push(&mut self, value: T) { let vec = unsafe{&mut *self.inner}; @@ -71,7 +71,7 @@ impl ScopedSection { pub(crate) fn len(&self) -> usize { let vec = unsafe{&mut *self.inner}; debug_assert_eq!(vec.len(), self.cur_size as usize, "trying to get section length, but size is larger than expected"); - return vec.len() - self.start_size; + return vec.len() - self.start_size as usize; } #[inline] @@ -85,23 +85,22 @@ impl ScopedSection { pub(crate) fn into_vec(self) -> Vec { let vec = unsafe{&mut *self.inner}; debug_assert_eq!(vec.len(), self.cur_size as usize, "trying to turn section into vec, but size is larger than expected"); - let section = Vec::from(&vec[self.start_size as usize..]); - vec.truncate(self.start_size as usize); + let section = Vec::from_iter(vec.drain(self.start_size as usize..)); section } } -impl std::ops::Index for ScopedSection { +impl std::ops::Index for ScopedSection { type Output = T; fn index(&self, idx: usize) -> &Self::Output { let vec = unsafe{&*self.inner}; - return vec[self.start_size as usize + idx] + return &vec[self.start_size as usize + idx] } } #[cfg(debug_assertions)] -impl Drop for ScopedSection { +impl Drop for ScopedSection { fn drop(&mut self) { // Make sure that the data was actually taken out of the scoped section let vec = unsafe{&*self.inner}; diff --git a/src/collections/string_pool.rs b/src/collections/string_pool.rs index c700c15b894d7824fa73bd03baf135b4d884ac6e..fb897861609d1cef87d11cc845c627fd07d968c8 100644 --- a/src/collections/string_pool.rs +++ b/src/collections/string_pool.rs @@ -1,6 +1,8 @@ use std::ptr::null_mut; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; +use std::fmt::{Debug, Display, Result as FmtResult}; +use crate::common::Formatter; const SLAB_SIZE: usize = u16::MAX as usize; @@ -11,6 +13,10 @@ pub struct StringRef<'a> { _phantom: PhantomData<&'a [u8]>, } +// As the StringRef is an immutable thing: +unsafe impl Sync for StringRef<'_> {} +unsafe impl Send for StringRef<'_> {} + impl<'a> StringRef<'a> { /// `new` constructs a new StringRef whose data is not owned by the /// `StringPool`, hence cannot have a `'static` lifetime. @@ -38,6 +44,20 @@ impl<'a> StringRef<'a> { } } +impl<'a> Debug for StringRef<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + f.write_str("StringRef{ value: ")?; + f.write_str(self.as_str())?; + f.write_str(" }") + } +} + +impl<'a> Display for StringRef<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + f.write_str(self.as_str()) + } +} + impl PartialEq for StringRef<'_> { fn eq(&self, other: &StringRef) -> bool { self.as_str() == other.as_str() @@ -48,9 +68,7 @@ impl Eq for StringRef<'_> {} impl Hash for StringRef<'_> { fn hash(&self, state: &mut H) { - unsafe{ - state.write(self.as_bytes()); - } + state.write(self.as_bytes()); } } diff --git a/src/protocol/ast.rs b/src/protocol/ast.rs index e1bfda4d72a28b6fb7a7ab8be073cd7a7efc199a..0d11efdc96bfcbe2dbcff96cba791079112126ea 100644 --- a/src/protocol/ast.rs +++ b/src/protocol/ast.rs @@ -58,6 +58,7 @@ macro_rules! define_new_ast_id { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct $name (pub(crate) $parent); + #[allow(dead_code)] impl $name { pub(crate) fn new_invalid() -> Self { Self(<$parent>::new_invalid()) } pub(crate) fn is_invalid(&self) -> bool { self.0.is_invalid() } @@ -356,7 +357,7 @@ impl Display for Identifier { } } -#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum ParserTypeVariant { // Basic builtin Message, @@ -379,16 +380,23 @@ pub enum ParserTypeVariant { impl ParserTypeVariant { pub(crate) fn num_embedded(&self) -> usize { + use ParserTypeVariant::*; + match self { - x if *x <= ParserTypeVariant::Inferred => 0, - x if *x <= ParserTypeVariant::Output => 1, - ParserTypeVariant::PolymorphicArgument(_, _) => 0, - ParserTypeVariant::Definition(_, num) => num, - _ => { debug_assert!(false); 0 }, + Message | Bool | + UInt8 | UInt16 | UInt32 | UInt64 | + SInt8 | SInt16 | SInt32 | SInt64 | + Character | String | IntegerLiteral | + Inferred | PolymorphicArgument(_, _) => + 0, + Array | Input | Output => + 1, + Definition(_, num) => *num, } } } +#[derive(Debug, Clone)] pub struct ParserTypeElement { // TODO: @cleanup, do we ever need the span of a user-defined type after // constructing it? @@ -405,6 +413,61 @@ pub struct ParserType { pub elements: Vec } +impl ParserType { + pub(crate) fn iter_embedded(&self, parent_idx: usize) -> ParserTypeIter { + ParserTypeIter::new(&self.elements, parent_idx) + } +} + +/// Iterator over the embedded elements of a specific element. +pub struct ParserTypeIter<'a> { + pub elements: &'a [ParserTypeElement], + pub cur_embedded_idx: usize, +} + +impl<'a> ParserTypeIter<'a> { + fn new(elements: &'a [ParserTypeElement], parent_idx: usize) -> Self { + debug_assert!(parent_idx < elements.len(), "parent index exceeds number of elements in ParserType"); + if elements[0].variant.num_embedded() == 0 { + // Parent element does not have any embedded types, place + // `cur_embedded_idx` at end so we will always return `None` + Self{ elements, cur_embedded_idx: elements.len() } + } else { + // Parent element has an embedded type + Self{ elements, cur_embedded_idx: parent_idx + 1 } + } + } +} + +impl<'a> Iterator for ParserTypeIter<'a> { + type Item = &'a [ParserTypeElement]; + + fn next(&mut self) -> Option { + let elements_len = self.elements.len(); + if self.cur_embedded_idx >= elements_len { + return None; + } + + // Seek to the end of the subtree + let mut depth = 1; + let start_element = self.cur_embedded_idx; + while self.cur_embedded_idx < elements_len { + let cur_element = &self.elements[self.cur_embedded_idx]; + let depth_change = cur_element.variant.num_embedded() as i32 - 1; + depth += depth_change; + debug_assert!(depth >= 0, "illegally constructed ParserType: {:?}", self.elements); + + self.cur_embedded_idx += 1; + if depth == 0 { + break; + } + } + + debug_assert!(depth == 0, "illegally constructed ParserType: {:?}", self.elements); + return Some(&self.elements[start_element..self.cur_embedded_idx]); + } +} + /// Specifies whether the symbolic type points to an actual user-defined type, /// or whether it points to a polymorphic argument within the definition (e.g. /// a defined variable `T var` within a function `int func()` @@ -776,19 +839,17 @@ impl Definition { } } pub fn parameters(&self) -> &Vec { - // TODO: Fix this - static EMPTY_VEC: Vec = Vec::new(); match self { Definition::Component(com) => &com.parameters, Definition::Function(fun) => &fun.parameters, - _ => &EMPTY_VEC, + _ => panic!("cannot retrieve parameters for {:?}", self), } } pub fn body(&self) -> BlockStatementId { match self { Definition::Component(com) => com.body, Definition::Function(fun) => fun.body, - _ => panic!("cannot retrieve body (for EnumDefinition/UnionDefinition or StructDefinition)") + _ => panic!("cannot retrieve body for {:?}", self), } } pub fn poly_vars(&self) -> &Vec { @@ -1209,7 +1270,7 @@ impl BlockStatement { // nested synchronous statements are flagged illegal, // and that happens before resolving variables that // creates the parent_scope references in the first place. - Some(h[parent].parent_scope(h).unwrap().to_block()) + Some(h[parent].parent_scope.unwrap().to_block()) } Scope::Regular(parent) => { // A variable scope is either a definition, sync, or block. @@ -1428,6 +1489,15 @@ pub enum ExpressionParent { Expression(ExpressionId, u32) // index within expression (e.g LHS or RHS of expression) } +impl ExpressionParent { + pub fn is_new(&self) -> bool { + match self { + ExpressionParent::New(_) => true, + _ => false, + } + } +} + #[derive(Debug, Clone)] pub enum Expression { Assignment(AssignmentExpression), @@ -1762,14 +1832,14 @@ pub struct CallExpression { pub this: CallExpressionId, // Phase 1: parser pub span: InputSpan, - pub parser_type: ParserType, // of the function call + pub parser_type: ParserType, // of the function call, not the return type pub method: Method, pub arguments: Vec, pub definition: DefinitionId, // Phase 2: linker pub parent: ExpressionParent, // Phase 3: type checking - pub concrete_type: ConcreteType, + pub concrete_type: ConcreteType, // of the return type } #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/src/protocol/ast_printer.rs b/src/protocol/ast_printer.rs index d991cbc9cae9a0e4bc20871e2b02ab6b41ddb734..870fcc4561addd9a82cddb3f22779646da3f7fb7 100644 --- a/src/protocol/ast_printer.rs +++ b/src/protocol/ast_printer.rs @@ -1,3 +1,5 @@ +#![allow(dead_code)] + use std::fmt::{Debug, Display, Write}; use std::io::Write as IOWrite; @@ -240,16 +242,14 @@ impl ASTWriter { self.kv(indent2).with_s_key("Name").with_identifier_val(&import.module); self.kv(indent2).with_s_key("Alias").with_identifier_val(&import.alias); - self.kv(indent2).with_s_key("Target") - .with_opt_disp_val(import.module_id.as_ref().map(|v| &v.index)); + self.kv(indent2).with_s_key("Target").with_disp_val(&import.module_id.index); }, Import::Symbols(import) => { self.kv(indent).with_id(PREFIX_IMPORT_ID, import.this.index) .with_s_key("ImportSymbol"); self.kv(indent2).with_s_key("Name").with_identifier_val(&import.module); - self.kv(indent2).with_s_key("Target") - .with_opt_disp_val(import.module_id.as_ref().map(|v| &v.index)); + self.kv(indent2).with_s_key("Target").with_disp_val(&import.module_id.index); self.kv(indent2).with_s_key("Symbols"); @@ -259,8 +259,7 @@ impl ASTWriter { self.kv(indent3).with_s_key("AliasedSymbol"); self.kv(indent4).with_s_key("Name").with_identifier_val(&symbol.name); self.kv(indent4).with_s_key("Alias").with_opt_identifier_val(symbol.alias.as_ref()); - self.kv(indent4).with_s_key("Definition") - .with_opt_disp_val(symbol.definition_id.as_ref().map(|v| &v.index)); + self.kv(indent4).with_s_key("Definition").with_disp_val(&symbol.definition_id.index); } } } @@ -526,8 +525,10 @@ impl ASTWriter { Statement::Return(stmt) => { self.kv(indent).with_id(PREFIX_RETURN_STMT_ID, stmt.this.0.index) .with_s_key("Return"); - self.kv(indent2).with_s_key("Expression"); - self.write_expr(heap, stmt.expression, indent3); + self.kv(indent2).with_s_key("Expressions"); + for expr_id in &stmt.expressions { + self.write_expr(heap, *expr_id, indent3); + } }, Statement::Goto(stmt) => { self.kv(indent).with_id(PREFIX_GOTO_STMT_ID, stmt.this.0.index) @@ -681,7 +682,11 @@ impl ASTWriter { Literal::True => { val.with_s_val("true"); }, Literal::False => { val.with_s_val("false"); }, Literal::Character(data) => { val.with_disp_val(data); }, - Literal::String(data) => { val.with_disp_val(data.as_str()); }, + Literal::String(data) => { + // Stupid hack + let string = String::from(data.as_str()); + val.with_disp_val(&string); + }, Literal::Integer(data) => { val.with_debug_val(data); }, Literal::Struct(data) => { val.with_s_val("Struct"); @@ -689,9 +694,7 @@ impl ASTWriter { self.kv(indent3).with_s_key("ParserType") .with_custom_val(|t| write_parser_type(t, heap, &data.parser_type)); - self.kv(indent3).with_s_key("Definition").with_custom_val(|s| { - write_option(s, data.definition.as_ref().map(|v| &v.index)); - }); + self.kv(indent3).with_s_key("Definition").with_disp_val(&data.definition.index); for field in &data.fields { self.kv(indent3).with_s_key("Field"); @@ -706,9 +709,7 @@ impl ASTWriter { self.kv(indent3).with_s_key("ParserType") .with_custom_val(|t| write_parser_type(t, heap, &data.parser_type)); - self.kv(indent3).with_s_key("Definition").with_custom_val(|s| { - write_option(s, data.definition.as_ref().map(|v| &v.index)) - }); + self.kv(indent3).with_s_key("Definition").with_disp_val(&data.definition.index); self.kv(indent3).with_s_key("VariantIdx").with_disp_val(&data.variant_idx); }, Literal::Union(data) => { @@ -717,9 +718,7 @@ impl ASTWriter { self.kv(indent3).with_s_key("ParserType") .with_custom_val(|t| write_parser_type(t, heap, &data.parser_type)); - self.kv(indent3).with_s_key("Definition").with_custom_val(|s| { - write_option(s, data.definition.as_ref().map(|v| &v.index)); - }); + self.kv(indent3).with_s_key("Definition").with_disp_val(&data.definition.index); self.kv(indent3).with_s_key("VariantIdx").with_disp_val(&data.variant_idx); for value in &data.values { @@ -866,12 +865,12 @@ fn write_parser_type(target: &mut String, heap: &Heap, t: &ParserType) { PTV::PolymorphicArgument(definition_id, arg_idx) => { let definition = &heap[*definition_id]; let poly_var = &definition.poly_vars()[*arg_idx].value; - target.write_str(poly_var.as_str()); + target.push_str(poly_var.as_str()); }, PTV::Definition(definition_id, num_embedded) => { let definition = &heap[*definition_id]; let definition_ident = definition.identifier().value.as_str(); - target.write_str(definition_ident); + target.push_str(definition_ident); let num_embedded = *num_embedded; if num_embedded != 0 { @@ -893,6 +892,7 @@ fn write_parser_type(target: &mut String, heap: &Heap, t: &ParserType) { write_element(target, heap, t, 0); } +// TODO: @Cleanup, this is littered at three places in the codebase fn write_concrete_type(target: &mut String, heap: &Heap, def_id: DefinitionId, t: &ConcreteType) { use ConcreteTypePart as CTP; @@ -912,11 +912,16 @@ fn write_concrete_type(target: &mut String, heap: &Heap, def_id: DefinitionId, t CTP::Void => target.push_str("void"), CTP::Message => target.push_str("msg"), CTP::Bool => target.push_str("bool"), - CTP::Byte => target.push_str("byte"), - CTP::Short => target.push_str("short"), - CTP::Int => target.push_str("int"), - CTP::Long => target.push_str("long"), - CTP::String => target.push_str("string"), + CTP::UInt8 => target.push_str(KW_TYPE_UINT8_STR), + CTP::UInt16 => target.push_str(KW_TYPE_UINT16_STR), + CTP::UInt32 => target.push_str(KW_TYPE_UINT32_STR), + CTP::UInt64 => target.push_str(KW_TYPE_UINT64_STR), + CTP::SInt8 => target.push_str(KW_TYPE_SINT8_STR), + CTP::SInt16 => target.push_str(KW_TYPE_SINT16_STR), + CTP::SInt32 => target.push_str(KW_TYPE_SINT32_STR), + CTP::SInt64 => target.push_str(KW_TYPE_SINT64_STR), + CTP::Character => target.push_str(KW_TYPE_CHAR_STR), + CTP::String => target.push_str(KW_TYPE_STRING_STR), CTP::Array => { idx = write_concrete_part(target, heap, def_id, t, idx + 1); target.push_str("[]"); @@ -963,7 +968,6 @@ fn write_expression_parent(target: &mut String, parent: &ExpressionParent) { EP::If(id) => format!("IfStmt({})", id.0.index), EP::While(id) => format!("WhileStmt({})", id.0.index), EP::Return(id) => format!("ReturnStmt({})", id.0.index), - EP::Assert(id) => format!("AssertStmt({})", id.0.index), EP::New(id) => format!("NewStmt({})", id.0.index), EP::ExpressionStmt(id) => format!("ExprStmt({})", id.0.index), EP::Expression(id, idx) => format!("Expr({}, {})", id.index, idx) diff --git a/src/protocol/eval.rs b/src/protocol/eval.rs index ea55369d378de1166cef1b73822aeba19ef47355..31c38fae23bf18e62912c32f05e01aa0f4d9c89f 100644 --- a/src/protocol/eval.rs +++ b/src/protocol/eval.rs @@ -24,10 +24,10 @@ const ONE: Value = Value::Byte(ByteValue(1)); // TODO: All goes one day anyway, so dirty typechecking hack trait ValueImpl { fn exact_type(&self) -> Type; - fn is_type_compatible(&self, h: &Heap, t: &ParserType) -> bool { + fn is_type_compatible(&self, h: &Heap, t: &[ParserTypeElement]) -> bool { Self::is_type_compatible_hack(h, t) } - fn is_type_compatible_hack(h: &Heap, t: &ParserType) -> bool; + fn is_type_compatible_hack(h: &Heap, t: &[ParserTypeElement]) -> bool; } #[derive(Debug, Clone)] @@ -93,7 +93,7 @@ impl Value { Literal::Struct(_data) => unimplemented!(), Literal::Enum(_data) => unimplemented!(), Literal::Union(_data) => unimplemented!(), - Literal::Array(expressions) => unimplemented!(), + Literal::Array(_expressions) => unimplemented!(), } } fn set(&mut self, index: &Value, value: &Value) -> Option { @@ -851,7 +851,7 @@ impl ValueImpl for Value { Value::LongArray(val) => val.exact_type(), } } - fn is_type_compatible(&self, h: &Heap, t: &ParserType) -> bool { + fn is_type_compatible(&self, h: &Heap, t: &[ParserTypeElement]) -> bool { match self { Value::Unassigned => true, Value::Input(_) => InputValue::is_type_compatible_hack(h, t), @@ -872,7 +872,7 @@ impl ValueImpl for Value { Value::LongArray(_) => LongArrayValue::is_type_compatible_hack(h, t), } } - fn is_type_compatible_hack(_h: &Heap, _t: &ParserType) -> bool { false } + fn is_type_compatible_hack(_h: &Heap, _t: &[ParserTypeElement]) -> bool { false } } impl Display for Value { @@ -914,9 +914,9 @@ impl ValueImpl for InputValue { fn exact_type(&self) -> Type { Type::INPUT } - fn is_type_compatible_hack(_h: &Heap, t: &ParserType) -> bool { + fn is_type_compatible_hack(_h: &Heap, t: &[ParserTypeElement]) -> bool { use ParserTypeVariant::*; - match &t.variant { + match &t[0].variant { Input | Inferred | Definition(_, _) => true, _ => false, } @@ -936,9 +936,9 @@ impl ValueImpl for OutputValue { fn exact_type(&self) -> Type { Type::OUTPUT } - fn is_type_compatible_hack(_h: &Heap, t: &ParserType) -> bool { + fn is_type_compatible_hack(_h: &Heap, t: &[ParserTypeElement]) -> bool { use ParserTypeVariant::*; - match &t.elements[0].variant { + match &t[0].variant { Output | Inferred | Definition(_, _) => true, _ => false, } @@ -968,9 +968,9 @@ impl ValueImpl for MessageValue { fn exact_type(&self) -> Type { Type::MESSAGE } - fn is_type_compatible_hack(_h: &Heap, t: &ParserType) -> bool { + fn is_type_compatible_hack(_h: &Heap, t: &[ParserTypeElement]) -> bool { use ParserTypeVariant::*; - match &t.elements[0].variant { + match &t[0].variant { Message | Inferred | Definition(_, _) => true, _ => false, } @@ -990,9 +990,9 @@ impl ValueImpl for BooleanValue { fn exact_type(&self) -> Type { Type::BOOLEAN } - fn is_type_compatible_hack(_h: &Heap, t: &ParserType) -> bool { + fn is_type_compatible_hack(_h: &Heap, t: &[ParserTypeElement]) -> bool { use ParserTypeVariant::*; - match t.elements[0].variant { + match &t[0].variant { Definition(_, _) | Inferred | Bool | UInt8 | UInt16 | UInt32 | UInt64 | SInt8 | SInt16 | SInt32 | SInt64 => true, @@ -1014,9 +1014,9 @@ impl ValueImpl for ByteValue { fn exact_type(&self) -> Type { Type::BYTE } - fn is_type_compatible_hack(_h: &Heap, t: &ParserType) -> bool { + fn is_type_compatible_hack(_h: &Heap, t: &[ParserTypeElement]) -> bool { use ParserTypeVariant::*; - match t.elements[0].variant { + match &t[0].variant { Definition(_, _) | Inferred | UInt8 | UInt16 | UInt32 | UInt64 | SInt8 | SInt16 | SInt32 | SInt64 => true, @@ -1038,9 +1038,9 @@ impl ValueImpl for ShortValue { fn exact_type(&self) -> Type { Type::SHORT } - fn is_type_compatible_hack(_h: &Heap, t: &ParserType) -> bool { + fn is_type_compatible_hack(_h: &Heap, t: &[ParserTypeElement]) -> bool { use ParserTypeVariant::*; - match t.elements[0].variant { + match &t[0].variant { Definition(_, _) | Inferred | UInt16 | UInt32 | UInt64 | SInt16 | SInt32 | SInt64=> true, @@ -1062,9 +1062,9 @@ impl ValueImpl for IntValue { fn exact_type(&self) -> Type { Type::INT } - fn is_type_compatible_hack(_h: &Heap, t: &ParserType) -> bool { + fn is_type_compatible_hack(_h: &Heap, t: &[ParserTypeElement]) -> bool { use ParserTypeVariant::*; - match t.elements[0].variant { + match t[0].variant { Definition(_, _) | Inferred | UInt32 | UInt64 | SInt32 | SInt64 => true, @@ -1086,18 +1086,18 @@ impl ValueImpl for LongValue { fn exact_type(&self) -> Type { Type::LONG } - fn is_type_compatible_hack(_h: &Heap, t: &ParserType) -> bool { + fn is_type_compatible_hack(_h: &Heap, t: &[ParserTypeElement]) -> bool { use ParserTypeVariant::*; - match &t.elements[0].variant { + match &t[0].variant { UInt64 | SInt64 | Inferred | Definition(_, _) => true, _ => false, } } } -fn get_array_inner(t: &ParserType) -> Option { - if t.elements[0].variant == ParserTypeVariant::Array { - return Some(t.elements[1].variant.clone()) +fn get_array_inner(t: &[ParserTypeElement]) -> Option<&[ParserTypeElement]> { + if t[0].variant == ParserTypeVariant::Array { + return Some(&t[1..]) } else { return None; } @@ -1125,9 +1125,9 @@ impl ValueImpl for InputArrayValue { fn exact_type(&self) -> Type { Type::INPUT_ARRAY } - fn is_type_compatible_hack(h: &Heap, t: &ParserType) -> bool { + fn is_type_compatible_hack(h: &Heap, t: &[ParserTypeElement]) -> bool { get_array_inner(t) - .map(|v| InputValue::is_type_compatible_hack(h, &h[v])) + .map(|v| InputValue::is_type_compatible_hack(h, v)) .unwrap_or(false) } } @@ -1154,9 +1154,9 @@ impl ValueImpl for OutputArrayValue { fn exact_type(&self) -> Type { Type::OUTPUT_ARRAY } - fn is_type_compatible_hack(h: &Heap, t: &ParserType) -> bool { + fn is_type_compatible_hack(h: &Heap, t: &[ParserTypeElement]) -> bool { get_array_inner(t) - .map(|v| OutputValue::is_type_compatible_hack(h, &h[v])) + .map(|v| OutputValue::is_type_compatible_hack(h, v)) .unwrap_or(false) } } @@ -1183,9 +1183,9 @@ impl ValueImpl for MessageArrayValue { fn exact_type(&self) -> Type { Type::MESSAGE_ARRAY } - fn is_type_compatible_hack(h: &Heap, t: &ParserType) -> bool { + fn is_type_compatible_hack(h: &Heap, t: &[ParserTypeElement]) -> bool { get_array_inner(t) - .map(|v| MessageValue::is_type_compatible_hack(h, &h[v])) + .map(|v| MessageValue::is_type_compatible_hack(h, v)) .unwrap_or(false) } } @@ -1212,9 +1212,9 @@ impl ValueImpl for BooleanArrayValue { fn exact_type(&self) -> Type { Type::BOOLEAN_ARRAY } - fn is_type_compatible_hack(h: &Heap, t: &ParserType) -> bool { + fn is_type_compatible_hack(h: &Heap, t: &[ParserTypeElement]) -> bool { get_array_inner(t) - .map(|v| BooleanValue::is_type_compatible_hack(h, &h[v])) + .map(|v| BooleanValue::is_type_compatible_hack(h, v)) .unwrap_or(false) } } @@ -1241,9 +1241,9 @@ impl ValueImpl for ByteArrayValue { fn exact_type(&self) -> Type { Type::BYTE_ARRAY } - fn is_type_compatible_hack(h: &Heap, t: &ParserType) -> bool { + fn is_type_compatible_hack(h: &Heap, t: &[ParserTypeElement]) -> bool { get_array_inner(t) - .map(|v| ByteValue::is_type_compatible_hack(h, &h[v])) + .map(|v| ByteValue::is_type_compatible_hack(h, v)) .unwrap_or(false) } } @@ -1270,9 +1270,9 @@ impl ValueImpl for ShortArrayValue { fn exact_type(&self) -> Type { Type::SHORT_ARRAY } - fn is_type_compatible_hack(h: &Heap, t: &ParserType) -> bool { + fn is_type_compatible_hack(h: &Heap, t: &[ParserTypeElement]) -> bool { get_array_inner(t) - .map(|v| ShortValue::is_type_compatible_hack(h, &h[v])) + .map(|v| ShortValue::is_type_compatible_hack(h, v)) .unwrap_or(false) } } @@ -1299,9 +1299,9 @@ impl ValueImpl for IntArrayValue { fn exact_type(&self) -> Type { Type::INT_ARRAY } - fn is_type_compatible_hack(h: &Heap, t: &ParserType) -> bool { + fn is_type_compatible_hack(h: &Heap, t: &[ParserTypeElement]) -> bool { get_array_inner(t) - .map(|v| IntValue::is_type_compatible_hack(h, &h[v])) + .map(|v| IntValue::is_type_compatible_hack(h, v)) .unwrap_or(false) } } @@ -1328,9 +1328,9 @@ impl ValueImpl for LongArrayValue { fn exact_type(&self) -> Type { Type::LONG_ARRAY } - fn is_type_compatible_hack(h: &Heap, t: &ParserType) -> bool { + fn is_type_compatible_hack(h: &Heap, t: &[ParserTypeElement]) -> bool { get_array_inner(t) - .map(|v| LongValue::is_type_compatible_hack(h, &h[v])) + .map(|v| LongValue::is_type_compatible_hack(h, v)) .unwrap_or(false) } } @@ -1349,7 +1349,7 @@ impl Store { Variable::Local(v) => &v.parser_type, Variable::Parameter(v) => &v.parser_type, }; - assert!(value.is_type_compatible(h, parser_type)); + assert!(value.is_type_compatible(h, &parser_type.elements)); // Overwrite mapping self.map.insert(var, value.clone()); } @@ -1368,7 +1368,7 @@ impl Store { Variable::Local(v) => &v.parser_type, Variable::Parameter(v) => &v.parser_type }; - assert!(value.is_type_compatible(h, parser_type)); + assert!(value.is_type_compatible(h, &parser_type.elements)); // Overwrite mapping self.map.insert(var, value.clone()); Ok(value) @@ -1458,7 +1458,7 @@ impl Store { } Ok(value) } - Expression::Binding(expr) => { + Expression::Binding(_expr) => { unimplemented!("eval binding expression"); } Expression::Conditional(expr) => { @@ -1561,8 +1561,22 @@ impl Store { assert_eq!(1, expr.arguments.len()); let length = self.eval(h, ctx, expr.arguments[0])?; Ok(Value::create_message(length)) - } - Method::Symbolic(_symbol) => unimplemented!(), + }, + Method::Length => { + todo!("implement") + }, + Method::Assert => { + let value = self.eval(h, ctx, expr.arguments[0])?; + if value.as_boolean().0 { + // Return bogus + Ok(Value::Unassigned) + } else { + // Failed assertion + Err(EvalContinuation::Inconsistent) + } + }, + Method::UserFunction => unimplemented!(), + Method::UserComponent => unreachable!(), }, Expression::Variable(expr) => self.get(h, ctx, expr.this.upcast()), } @@ -1602,7 +1616,7 @@ impl Prompt { assert_eq!(params.len(), args.len()); for (param, value) in params.iter().zip(args.iter()) { let hparam = &h[*param]; - assert!(value.is_type_compatible(h, &hparam.parser_type)); + assert!(value.is_type_compatible(h, &hparam.parser_type.elements)); self.store.initialize(h, param.upcast(), value.clone()); } } @@ -1635,11 +1649,6 @@ impl Prompt { self.position = stmt.next(); Err(EvalContinuation::Stepping) } - Statement::Skip(stmt) => { - // Continue to next statement - self.position = stmt.next; - Err(EvalContinuation::Stepping) - } Statement::Labeled(stmt) => { // Continue to next statement self.position = Some(stmt.body); @@ -1700,21 +1709,10 @@ impl Prompt { self.position = stmt.target.map(WhileStatementId::upcast); Err(EvalContinuation::Stepping) } - Statement::Assert(stmt) => { - // Evaluate expression - let value = self.store.eval(h, ctx, stmt.expression)?; - if value.as_boolean().0 { - // Continue to next statement - self.position = stmt.next; - Err(EvalContinuation::Stepping) - } else { - // Assertion failed: inconsistent - Err(EvalContinuation::Inconsistent) - } - } Statement::Return(stmt) => { // Evaluate expression - let value = self.store.eval(h, ctx, stmt.expression)?; + debug_assert_eq!(stmt.expressions.len(), 1); + let value = self.store.eval(h, ctx, stmt.expressions[0])?; // Done with evaluation Ok(value) } @@ -1732,8 +1730,8 @@ impl Prompt { } self.position = stmt.next; match &expr.method { - Method::Symbolic(symbolic) => { - Err(EvalContinuation::NewComponent(symbolic.definition.unwrap(), args)) + Method::UserComponent => { + Err(EvalContinuation::NewComponent(expr.definition, args)) }, _ => unreachable!("not a symbolic call expression") } diff --git a/src/protocol/input_source.rs b/src/protocol/input_source.rs index 3de5ce2533f3319f82c4716cfb7d53d7080a7c4f..c6abc1f440c844c938344f1d180c9695e20b594b 100644 --- a/src/protocol/input_source.rs +++ b/src/protocol/input_source.rs @@ -1,5 +1,5 @@ use std::fmt; -use std::cell::{Ref, RefCell}; +use std::sync::{RwLock, RwLockReadGuard}; use std::fmt::Write; #[derive(Debug, Clone, Copy)] @@ -38,9 +38,9 @@ pub struct InputSource { // State tracking pub(crate) had_error: Option, // The offset_lookup is built on-demand upon attempting to report an error. - // As the compiler is currently not multithreaded, we simply put it in a - // RefCell to allow interior mutability. - offset_lookup: RefCell>, + // Only one procedure will actually create the lookup, afterwards only read + // locks will be held. + offset_lookup: RwLock>, } impl InputSource { @@ -51,7 +51,7 @@ impl InputSource { line: 1, offset: 0, had_error: None, - offset_lookup: RefCell::new(Vec::new()), + offset_lookup: RwLock::new(Vec::new()), } } @@ -129,18 +129,28 @@ impl InputSource { } } - fn get_lookup(&self) -> Ref> { + fn get_lookup(&self) -> RwLockReadGuard> { // Once constructed the lookup always contains one element. We use this // to see if it is constructed already. - let lookup = self.offset_lookup.borrow(); + { + let lookup = self.offset_lookup.read().unwrap(); + if !lookup.is_empty() { + return lookup; + } + } + + // Lookup was not constructed yet + let mut lookup = self.offset_lookup.write().unwrap(); if !lookup.is_empty() { + // Somebody created it before we had the chance + drop(lookup); + let lookup = self.offset_lookup.read().unwrap(); return lookup; } // Build the line number (!) to offset lookup, so offset by 1. We // assume the entire source file is scanned (most common case) for // preallocation. - let mut lookup = self.offset_lookup.borrow_mut(); lookup.reserve(self.line as usize + 2); lookup.push(0); // line 0: never used lookup.push(0); // first line: first character @@ -155,7 +165,8 @@ impl InputSource { debug_assert_eq!(self.line as usize + 2, lookup.len(), "remove me: i am a testing assert and sometimes invalid"); // Return created lookup - let lookup = self.offset_lookup.borrow(); + drop(lookup); + let lookup = self.offset_lookup.read().unwrap(); return lookup; } @@ -355,7 +366,7 @@ impl fmt::Display for ParseErrorStatement { while let Some(cur_line) = lines.next() { context.clear(); transform_context(cur_line, &mut context); - writeln!(f, " | {}", &context); + writeln!(f, " | {}", &context)?; last_line = cur_line; } @@ -393,10 +404,6 @@ impl fmt::Display for ParseError { } impl ParseError { - pub fn empty() -> Self { - Self{ statements: Vec::new() } - } - pub fn new_error_at_pos(source: &InputSource, position: InputPosition, message: String) -> Self { Self{ statements: vec!(ParseErrorStatement::from_source_at_pos( StatementKind::Error, source, position, message diff --git a/src/protocol/parser/pass_definitions.rs b/src/protocol/parser/pass_definitions.rs index 9bc32f1e501abf47eb6c86f359c5a42b21b683bb..3da96eecbed9bbe208c92967d27e68b71e51c73f 100644 --- a/src/protocol/parser/pass_definitions.rs +++ b/src/protocol/parser/pass_definitions.rs @@ -12,9 +12,9 @@ pub(crate) struct PassDefinitions { cur_definition: DefinitionId, // Temporary buffers of various kinds buffer: String, - struct_fields: Vec, - enum_variants: Vec, - union_variants: Vec, + struct_fields: ScopedBuffer, + enum_variants: ScopedBuffer, + union_variants: ScopedBuffer, parameters: ScopedBuffer, expressions: ScopedBuffer, statements: ScopedBuffer, @@ -26,9 +26,9 @@ impl PassDefinitions { Self{ cur_definition: DefinitionId::new_invalid(), buffer: String::with_capacity(128), - struct_fields: Vec::with_capacity(128), - enum_variants: Vec::with_capacity(128), - union_variants: Vec::with_capacity(128), + struct_fields: ScopedBuffer::new_reserved(128), + enum_variants: ScopedBuffer::new_reserved(128), + union_variants: ScopedBuffer::new_reserved(128), parameters: ScopedBuffer::new_reserved(128), expressions: ScopedBuffer::new_reserved(128), statements: ScopedBuffer::new_reserved(128), @@ -89,6 +89,7 @@ impl PassDefinitions { match ident { Some(KW_STRUCT) => self.visit_struct_definition(module, &mut iter, ctx)?, Some(KW_ENUM) => self.visit_enum_definition(module, &mut iter, ctx)?, + Some(KW_UNION) => self.visit_union_definition(module, &mut iter, ctx)?, Some(KW_FUNCTION) => self.visit_function_definition(module, &mut iter, ctx)?, Some(KW_PRIMITIVE) | Some(KW_COMPOSITE) => self.visit_component_definition(module, &mut iter, ctx)?, _ => return Err(ParseError::new_error_str_at_pos( @@ -109,14 +110,16 @@ impl PassDefinitions { let module_scope = SymbolScope::Module(module.root_id); let definition_id = ctx.symbols.get_symbol_by_name_defined_in_scope(module_scope, ident_text) .unwrap().variant.as_definition().definition_id; - let poly_vars = ctx.heap[definition_id].poly_vars(); // Parse struct definition - consume_polymorphic_vars_spilled(&module.source, iter)?; - debug_assert!(self.struct_fields.is_empty()); + consume_polymorphic_vars_spilled(&module.source, iter, ctx)?; + + let mut fields_section = self.struct_fields.start_section(); consume_comma_separated( - TokenKind::OpenCurly, TokenKind::CloseCurly, &module.source, iter, - |source, iter| { + TokenKind::OpenCurly, TokenKind::CloseCurly, &module.source, iter, ctx, + |source, iter, ctx| { + let poly_vars = ctx.heap[definition_id].poly_vars(); // TODO: @Cleanup, this is really ugly. But rust... + let start_pos = iter.last_valid_pos(); let parser_type = consume_parser_type( source, iter, &ctx.symbols, &ctx.heap, poly_vars, module_scope, @@ -128,13 +131,12 @@ impl PassDefinitions { field, parser_type }) }, - &mut self.struct_fields, "a struct field", "a list of struct fields", None + &mut fields_section, "a struct field", "a list of struct fields", None )?; // Transfer to preallocated definition let struct_def = ctx.heap[definition_id].as_struct_mut(); - struct_def.fields.clone_from(&self.struct_fields); - self.struct_fields.clear(); + struct_def.fields = fields_section.into_vec(); Ok(()) } @@ -149,14 +151,14 @@ impl PassDefinitions { let module_scope = SymbolScope::Module(module.root_id); let definition_id = ctx.symbols.get_symbol_by_name_defined_in_scope(module_scope, ident_text) .unwrap().variant.as_definition().definition_id; - let poly_vars = ctx.heap[definition_id].poly_vars(); // Parse enum definition - consume_polymorphic_vars_spilled(&module.source, iter)?; - debug_assert!(self.enum_variants.is_empty()); + consume_polymorphic_vars_spilled(&module.source, iter, ctx)?; + + let mut enum_section = self.enum_variants.start_section(); consume_comma_separated( - TokenKind::OpenCurly, TokenKind::CloseCurly, &module.source, iter, - |source, iter| { + TokenKind::OpenCurly, TokenKind::CloseCurly, &module.source, iter, ctx, + |source, iter, ctx| { let identifier = consume_ident_interned(source, iter, ctx)?; let value = if iter.next() == Some(TokenKind::Equal) { iter.consume(); @@ -167,13 +169,12 @@ impl PassDefinitions { }; Ok(EnumVariantDefinition{ identifier, value }) }, - &mut self.enum_variants, "an enum variant", "a list of enum variants", None + &mut enum_section, "an enum variant", "a list of enum variants", None )?; // Transfer to definition let enum_def = ctx.heap[definition_id].as_enum_mut(); - enum_def.variants.clone_from(&self.enum_variants); - self.enum_variants.clear(); + enum_def.variants = enum_section.into_vec(); Ok(()) } @@ -188,19 +189,21 @@ impl PassDefinitions { let module_scope = SymbolScope::Module(module.root_id); let definition_id = ctx.symbols.get_symbol_by_name_defined_in_scope(module_scope, ident_text) .unwrap().variant.as_definition().definition_id; - let poly_vars = ctx.heap[definition_id].poly_vars(); // Parse union definition - consume_polymorphic_vars_spilled(&module.source, iter)?; - debug_assert!(self.union_variants.is_empty()); + consume_polymorphic_vars_spilled(&module.source, iter, ctx)?; + + let mut variants_section = self.union_variants.start_section(); consume_comma_separated( - TokenKind::OpenCurly, TokenKind::CloseCurly, &module.source, iter, - |source, iter| { + TokenKind::OpenCurly, TokenKind::CloseCurly, &module.source, iter, ctx, + |source, iter, ctx| { let identifier = consume_ident_interned(source, iter, ctx)?; let mut close_pos = identifier.span.end; + let has_embedded = maybe_consume_comma_separated( - TokenKind::OpenParen, TokenKind::CloseParen, source, iter, - |source, iter| { + TokenKind::OpenParen, TokenKind::CloseParen, source, iter, ctx, + |source, iter, ctx| { + let poly_vars = ctx.heap[definition_id].poly_vars(); // TODO: @Cleanup, this is really ugly. But rust... consume_parser_type( source, iter, &ctx.symbols, &ctx.heap, poly_vars, module_scope, definition_id, false, 0 @@ -221,13 +224,12 @@ impl PassDefinitions { value }) }, - &mut self.union_variants, "a union variant", "a list of union variants", None + &mut variants_section, "a union variant", "a list of union variants", None )?; // Transfer to AST let union_def = ctx.heap[definition_id].as_union_mut(); - union_def.variants.clone_from(&self.union_variants); - self.union_variants.clear(); + union_def.variants = variants_section.into_vec(); Ok(()) } @@ -242,12 +244,11 @@ impl PassDefinitions { let module_scope = SymbolScope::Module(module.root_id); let definition_id = ctx.symbols.get_symbol_by_name_defined_in_scope(module_scope, ident_text) .unwrap().variant.as_definition().definition_id; - let poly_vars = ctx.heap[definition_id].poly_vars(); // Parse function's argument list let mut parameter_section = self.parameters.start_section(); consume_parameter_list( - &module.source, iter, ctx, &mut parameter_section, poly_vars, module_scope, definition_id + &module.source, iter, ctx, &mut parameter_section, module_scope, definition_id )?; let parameters = parameter_section.into_vec(); @@ -255,8 +256,9 @@ impl PassDefinitions { consume_token(&module.source, iter, TokenKind::ArrowRight)?; let mut open_curly_pos = iter.last_valid_pos(); consume_comma_separated_until( - TokenKind::OpenCurly, &module.source, iter, - |source, iter| { + TokenKind::OpenCurly, &module.source, iter, ctx, + |source, iter, ctx| { + let poly_vars = ctx.heap[definition_id].poly_vars(); // TODO: @Cleanup, this is really ugly. But rust... consume_parser_type(source, iter, &ctx.symbols, &ctx.heap, poly_vars, module_scope, definition_id, false, 0) }, &mut self.parser_types, "a return type", Some(&mut open_curly_pos) @@ -293,12 +295,11 @@ impl PassDefinitions { let module_scope = SymbolScope::Module(module.root_id); let definition_id = ctx.symbols.get_symbol_by_name_defined_in_scope(module_scope, ident_text) .unwrap().variant.as_definition().definition_id; - let poly_vars = ctx.heap[definition_id].poly_vars(); // Parse component's argument list let mut parameter_section = self.parameters.start_section(); consume_parameter_list( - &module.source, iter, ctx, &mut parameter_section, poly_vars, module_scope, definition_id + &module.source, iter, ctx, &mut parameter_section, module_scope, definition_id )?; let parameters = parameter_section.into_vec(); @@ -438,12 +439,19 @@ impl PassDefinitions { fn consume_block_statement_without_leading_curly( &mut self, module: &Module, iter: &mut TokenIter, ctx: &mut PassCtx, open_curly_pos: InputPosition ) -> Result { - let mut statements = Vec::new(); + let mut stmt_section = self.statements.start_section(); let mut next = iter.next(); - while next.is_some() && next != Some(TokenKind::CloseCurly) { - + while next != Some(TokenKind::CloseCurly) { + if next.is_none() { + return Err(ParseError::new_error_str_at_pos( + &module.source, iter.last_valid_pos(), "expected a statement or '}'" + )); + } + self.consume_statement(module, iter, ctx, &mut stmt_section)?; + next = iter.next(); } + let statements = stmt_section.into_vec(); let mut block_span = consume_token(&module.source, iter, TokenKind::CloseCurly)?; block_span.begin = open_curly_pos; @@ -565,14 +573,16 @@ impl PassDefinitions { let mut scoped_section = self.expressions.start_section(); consume_comma_separated_until( - TokenKind::SemiColon, &module.source, iter, - |source, iter| self.consume_expression(module, iter, ctx), + TokenKind::SemiColon, &module.source, iter, ctx, + |_source, iter, ctx| self.consume_expression(module, iter, ctx), &mut scoped_section, "a return expression", None )?; let expressions = scoped_section.into_vec(); if expressions.is_empty() { return Err(ParseError::new_error_str_at_span(&module.source, return_span, "expected at least one return value")); + } else if expressions.len() > 1 { + return Err(ParseError::new_error_str_at_span(&module.source, return_span, "multiple return values are not (yet) supported")) } Ok(ctx.heap.alloc_return_statement(|this| ReturnStatement{ @@ -1190,8 +1200,8 @@ impl PassDefinitions { let (start_pos, mut end_pos) = iter.next_positions(); let mut scoped_section = self.expressions.start_section(); consume_comma_separated( - TokenKind::OpenCurly, TokenKind::CloseCurly, &module.source, iter, - |source, iter| self.consume_expression(module, iter, ctx), + TokenKind::OpenCurly, TokenKind::CloseCurly, &module.source, iter, ctx, + |_source, iter, ctx| self.consume_expression(module, iter, ctx), &mut scoped_section, "an expression", "a list of expressions", Some(&mut end_pos) )?; @@ -1260,8 +1270,8 @@ impl PassDefinitions { let mut last_token = iter.last_valid_pos(); let mut struct_fields = Vec::new(); consume_comma_separated( - TokenKind::OpenCurly, TokenKind::CloseCurly, &module.source, iter, - |source, iter| { + TokenKind::OpenCurly, TokenKind::CloseCurly, &module.source, iter, ctx, + |source, iter, ctx| { let identifier = consume_ident_interned(source, iter, ctx)?; consume_token(source, iter, TokenKind::Colon)?; let value = self.consume_expression(module, iter, ctx)?; @@ -1337,9 +1347,6 @@ impl PassDefinitions { }).upcast() }, Definition::Function(function_definition) => { - // Function call: consume the arguments - let arguments = self.consume_expression_list(module, iter, ctx, None)?; - // Check whether it is a builtin function let method = if function_definition.builtin { match function_definition.identifier.value.as_str() { @@ -1355,6 +1362,9 @@ impl PassDefinitions { Method::UserFunction }; + // Function call: consume the arguments + let arguments = self.consume_expression_list(module, iter, ctx, None)?; + ctx.heap.alloc_call_expression(|this| CallExpression{ this, span: parser_type.elements[0].full_span, // TODO: @Span fix @@ -1460,8 +1470,8 @@ impl PassDefinitions { ) -> Result, ParseError> { let mut section = self.expressions.start_section(); consume_comma_separated( - TokenKind::OpenParen, TokenKind::CloseParen, &module.source, iter, - |source, iter| self.consume_expression(module, iter, ctx), + TokenKind::OpenParen, TokenKind::CloseParen, &module.source, iter, ctx, + |_source, iter, ctx| self.consume_expression(module, iter, ctx), &mut section, "an expression", "a list of expressions", end_pos )?; Ok(section.into_vec()) @@ -1807,10 +1817,10 @@ fn consume_parser_type_ident( } /// Consumes polymorphic variables and throws them on the floor. -fn consume_polymorphic_vars_spilled(source: &InputSource, iter: &mut TokenIter) -> Result<(), ParseError> { +fn consume_polymorphic_vars_spilled(source: &InputSource, iter: &mut TokenIter, _ctx: &mut PassCtx) -> Result<(), ParseError> { maybe_consume_comma_separated_spilled( - TokenKind::OpenAngle, TokenKind::CloseAngle, source, iter, - |source, iter| { + TokenKind::OpenAngle, TokenKind::CloseAngle, source, iter, _ctx, + |source, iter, _ctx| { consume_ident(source, iter)?; Ok(()) }, "a polymorphic variable" @@ -1820,12 +1830,13 @@ fn consume_polymorphic_vars_spilled(source: &InputSource, iter: &mut TokenIter) /// Consumes the parameter list to functions/components fn consume_parameter_list( - source: &InputSource, iter: &mut TokenIter, ctx: &mut PassCtx, target: &mut ScopedSection, - poly_vars: &[Identifier], scope: SymbolScope, definition_id: DefinitionId + source: &InputSource, iter: &mut TokenIter, ctx: &mut PassCtx, + target: &mut ScopedSection, scope: SymbolScope, definition_id: DefinitionId ) -> Result<(), ParseError> { consume_comma_separated( - TokenKind::OpenParen, TokenKind::CloseParen, source, iter, - |source, iter| { + TokenKind::OpenParen, TokenKind::CloseParen, source, iter, ctx, + |source, iter, ctx| { + let poly_vars = ctx.heap[definition_id].poly_vars(); // TODO: @Cleanup, this is really ugly. But rust... let (start_pos, _) = iter.next_positions(); let parser_type = consume_parser_type( source, iter, &ctx.symbols, &ctx.heap, poly_vars, scope, diff --git a/src/protocol/parser/pass_imports.rs b/src/protocol/parser/pass_imports.rs index 00c833d2299b5fce7aa9eeb342875571483f6574..a480ca60baeb3fef9c7eeb2c6447ba3f539e0fc7 100644 --- a/src/protocol/parser/pass_imports.rs +++ b/src/protocol/parser/pass_imports.rs @@ -55,7 +55,7 @@ impl PassImport { } pub(crate) fn visit_import_range( - &mut self, modules: &mut [Module], module_idx: usize, ctx: &mut PassCtx, range_idx: usize + &mut self, modules: &[Module], module_idx: usize, ctx: &mut PassCtx, range_idx: usize ) -> Result<(), ParseError> { let module = &modules[module_idx]; let import_range = &module.tokens.ranges[range_idx]; @@ -116,6 +116,16 @@ impl PassImport { ) -> Result<(AliasedSymbol, SymbolDefinition), ParseError> { // Consume symbol name and make sure it points to an existing definition let symbol_identifier = consume_ident_interned(source, iter, ctx)?; + + // Consume alias text if specified + let alias_identifier = if peek_ident(source, iter) == Some(b"as") { + // Consume alias + iter.consume(); + Some(consume_ident_interned(source, iter, ctx)?) + } else { + None + }; + let target = ctx.symbols.get_symbol_by_name_defined_in_scope( SymbolScope::Module(module_root_id), symbol_identifier.value.as_bytes() ); @@ -133,15 +143,6 @@ impl PassImport { debug_assert_ne!(target.class(), SymbolClass::Module); let target_definition = target.variant.as_definition(); - // Consume alias text if specified - let alias_identifier = if peek_ident(source, iter) == b"as" { - // Consume alias - iter.consume(); - Some(consume_ident_interned(source, iter, ctx)?) - } else { - None - }; - Ok(( AliasedSymbol{ name: symbol_identifier, @@ -160,7 +161,12 @@ impl PassImport { let (imported_symbol, symbol_definition) = consume_symbol_and_maybe_alias( &module.source, &mut iter, ctx, &module_identifier.value, target_root_id )?; - let alias_identifier = imported_symbol.alias.unwrap_or_else(|| { imported_symbol.name.clone() }); + + let alias_identifier = match imported_symbol.alias.as_ref() { + Some(alias) => alias.clone(), + None => imported_symbol.name.clone(), + }; + import_id = ctx.heap.alloc_import(|this| Import::Symbols(ImportSymbols{ this, span: InputSpan::from_positions(import_span.begin, alias_identifier.span.end), @@ -176,15 +182,15 @@ impl PassImport { } ) { return Err(construct_symbol_conflict_error( - modules, module_idx, ctx, &new_symbol, old_symbol + modules, module_idx, ctx, &new_symbol, &old_symbol )); } } else if Some(TokenKind::OpenCurly) == next { // Importing multiple symbols let mut end_of_list = iter.last_valid_pos(); consume_comma_separated( - TokenKind::OpenCurly, TokenKind::CloseCurly, &module.source, &mut iter, - |source, iter| consume_symbol_and_maybe_alias( + TokenKind::OpenCurly, TokenKind::CloseCurly, &module.source, &mut iter, ctx, + |source, iter, ctx| consume_symbol_and_maybe_alias( source, iter, ctx, &module_identifier.value, target_root_id ), &mut self.found_symbols, "a symbol", "a list of symbols to import", Some(&mut end_of_list) @@ -204,10 +210,11 @@ impl PassImport { let import = ctx.heap[import_id].as_symbols_mut(); for (imported_symbol, symbol_definition) in self.found_symbols.drain(..) { - let import_name = imported_symbol.alias.map_or_else( - || imported_symbol.name.value.clone(), - |v| v.value.clone() - ); + let import_name = match imported_symbol.alias.as_ref() { + Some(import) => import.value.clone(), + None => imported_symbol.name.value.clone() + }; + import.symbols.push(imported_symbol); if let Err((new_symbol, old_symbol)) = ctx.symbols.insert_symbol( SymbolScope::Module(module.root_id), Symbol{ @@ -215,7 +222,7 @@ impl PassImport { variant: SymbolVariant::Definition(symbol_definition.into_imported(import_id)) } ) { - return Err(construct_symbol_conflict_error(modules, module_idx, ctx, &new_symbol, old_symbol)); + return Err(construct_symbol_conflict_error(modules, module_idx, ctx, &new_symbol, &old_symbol)); } } } else if Some(TokenKind::Star) == next { @@ -247,7 +254,7 @@ impl PassImport { match symbol.variant { SymbolVariant::Definition(symbol_definition) => { import.symbols.push(AliasedSymbol{ - name: Identifier{ span: star_span, value: symbol.name.clone() }, + name: Identifier{ span: star_span, value: symbol_name.clone() }, alias: None, definition_id: symbol_definition.definition_id, }); @@ -259,7 +266,7 @@ impl PassImport { variant: SymbolVariant::Definition(symbol_definition.into_imported(import_id)) } ) { - return Err(construct_symbol_conflict_error(modules, module_idx, ctx, &new_symbol, old_symbol)); + return Err(construct_symbol_conflict_error(modules, module_idx, ctx, &new_symbol, &old_symbol)); } }, _ => unreachable!(), @@ -289,13 +296,15 @@ impl PassImport { alias: alias_identifier, module_id: target_root_id, })); - ctx.symbols.insert_symbol(SymbolScope::Module(module.root_id), Symbol{ + if let Err((new_symbol, old_symbol)) = ctx.symbols.insert_symbol(SymbolScope::Module(module.root_id), Symbol{ name: alias, variant: SymbolVariant::Module(SymbolModule{ root_id: target_root_id, introduced_at: import_id }) - }); + }) { + return Err(construct_symbol_conflict_error(modules, module_idx, ctx, &new_symbol, &old_symbol)); + } } // By now the `import_id` is set, just need to make sure that the import diff --git a/src/protocol/parser/pass_symbols.rs b/src/protocol/parser/pass_symbols.rs index c4cd05cf89a14395488dc57f37390a64cfe4e42e..8d7fa84e4423d53074dfd094c87d3cc0e471a84a 100644 --- a/src/protocol/parser/pass_symbols.rs +++ b/src/protocol/parser/pass_symbols.rs @@ -62,20 +62,25 @@ impl PassSymbols { }); module.root_id = root_id; - // Visit token ranges to detect definitions and pragmas + // Retrieve first range index, then make immutable borrow let mut range_idx = module_range.first_child_idx; + let module = &modules[module_idx]; + + // Visit token ranges to detect definitions and pragmas loop { let range_idx_usize = range_idx as usize; let cur_range = &module.tokens.ranges[range_idx_usize]; + let next_sibling_idx = cur_range.next_sibling_idx; + let range_kind = cur_range.range_kind; // Parse if it is a definition or a pragma - if cur_range.range_kind == TokenRangeKind::Definition { + if range_kind == TokenRangeKind::Definition { self.visit_definition_range(modules, module_idx, ctx, range_idx_usize)?; - } else if cur_range.range_kind == TokenRangeKind::Pragma { + } else if range_kind == TokenRangeKind::Pragma { self.visit_pragma_range(modules, module_idx, ctx, range_idx_usize)?; } - match cur_range.next_sibling_idx { + match next_sibling_idx { Some(idx) => { range_idx = idx; }, None => { break; }, } @@ -86,7 +91,7 @@ impl PassSymbols { ctx.symbols.insert_scope(None, module_scope); for symbol in self.symbols.drain(..) { if let Err((new_symbol, old_symbol)) = ctx.symbols.insert_symbol(module_scope, symbol) { - return Err(construct_symbol_conflict_error(modules, module_idx, ctx, &new_symbol, old_symbol)) + return Err(construct_symbol_conflict_error(modules, module_idx, ctx, &new_symbol, &old_symbol)) } } @@ -94,6 +99,8 @@ impl PassSymbols { let root = &mut ctx.heap[root_id]; root.pragmas.extend(self.pragmas.drain(..)); root.definitions.extend(self.definitions.drain(..)); + + let module = &mut modules[module_idx]; module.phase = ModuleCompilationPhase::SymbolsScanned; Ok(()) @@ -134,7 +141,7 @@ impl PassSymbols { // Naming conflict let this_module = &modules[module_idx]; let other_module = seek_module(modules, other_module_root_id).unwrap(); - let (other_module_pragma_id, _) = other_module.name.unwrap(); + let other_module_pragma_id = other_module.name.as_ref().map(|v| (*v).0).unwrap(); let other_pragma = ctx.heap[other_module_pragma_id].as_module(); return Err(ParseError::new_error_str_at_span( &this_module.source, pragma_span, "conflict in module name" @@ -183,8 +190,8 @@ impl PassSymbols { let identifier = consume_ident_interned(&module.source, &mut iter, ctx)?; let mut poly_vars = Vec::new(); maybe_consume_comma_separated( - TokenKind::OpenAngle, TokenKind::CloseAngle, &module.source, &mut iter, - |source, iter| consume_ident_interned(source, iter, ctx), + TokenKind::OpenAngle, TokenKind::CloseAngle, &module.source, &mut iter, ctx, + |source, iter, ctx| consume_ident_interned(source, iter, ctx), &mut poly_vars, "a polymorphic variable", None )?; let ident_text = identifier.value.clone(); // because we need it later diff --git a/src/protocol/parser/pass_tokenizer.rs b/src/protocol/parser/pass_tokenizer.rs index a71cbfef685bc89dc427e87410acb5a8995fc707..904b0d4526e1adfd73f66476b58a75d23a521da9 100644 --- a/src/protocol/parser/pass_tokenizer.rs +++ b/src/protocol/parser/pass_tokenizer.rs @@ -2,7 +2,6 @@ use crate::protocol::input_source::{ InputSource as InputSource, ParseError, InputPosition as InputPosition, - InputSpan }; use super::tokens::*; @@ -157,7 +156,7 @@ impl PassTokenizer { assert_ne!(cur_range.last_child_idx, parent_idx as u32); let mut child_counter = 0u32; - let mut last_child_idx = cur_range.first_child_idx; + let last_child_idx = cur_range.first_child_idx; let mut child_idx = Some(cur_range.first_child_idx); while let Some(cur_child_idx) = child_idx { let child_range = &target.ranges[cur_child_idx as usize]; @@ -372,7 +371,10 @@ impl PassTokenizer { } } else if first_char == b'}' { source.consume(); - token_kind = TokenKind::CloseCurly + token_kind = TokenKind::CloseCurly; + } else if first_char == b'~' { + source.consume(); + token_kind = TokenKind::Tilde; } else { self.check_ascii(source)?; return Ok(None); @@ -626,6 +628,7 @@ impl PassTokenizer { /// Pushes a new token range onto the stack in the buffers. fn push_range(&mut self, target: &mut TokenBuffer, range_kind: TokenRangeKind, first_token: u32) { + let new_range_idx = target.ranges.len() as u32; let cur_range = &mut target.ranges[self.stack_idx]; // If we have just popped a range and then push a new range, then the @@ -635,14 +638,13 @@ impl PassTokenizer { // intermediate "code" range. if cur_range.end != first_token { let code_start = cur_range.end; - let code_range_idx = target.ranges.len() as u32; if cur_range.first_child_idx == self.stack_idx as u32 { // The parent of the new "code" range we're going to push does // not have any registered children yet. - cur_range.first_child_idx = code_range_idx; + cur_range.first_child_idx = new_range_idx; } - cur_range.last_child_idx = code_range_idx + 1; + cur_range.last_child_idx = new_range_idx + 1; cur_range.end = first_token; cur_range.num_child_ranges += 1; @@ -653,15 +655,14 @@ impl PassTokenizer { start: code_start, end: first_token, num_child_ranges: 0, - first_child_idx: code_range_idx, - last_child_idx: code_range_idx, - next_sibling_idx: Some(code_range_idx + 1), // we're going to push this thing next + first_child_idx: new_range_idx, + last_child_idx: new_range_idx, + next_sibling_idx: Some(new_range_idx + 1), // we're going to push this thing next }); } else { // We're going to push the range in the code below, but while we // have the `cur_range` borrowed mutably, we fix up its children // indices. - let new_range_idx = target.ranges.len() as u32; if cur_range.first_child_idx == self.stack_idx as u32 { cur_range.first_child_idx = new_range_idx; } diff --git a/src/protocol/parser/pass_typing.rs b/src/protocol/parser/pass_typing.rs index 2f486ae045906454008c3ca1c30052576a06c510..3b3db1e4e2fa010ceaa6583387d9739fe22ecaab 100644 --- a/src/protocol/parser/pass_typing.rs +++ b/src/protocol/parser/pass_typing.rs @@ -60,6 +60,7 @@ use crate::protocol::ast::*; use crate::protocol::input_source::ParseError; use crate::protocol::parser::ModuleCompilationPhase; use crate::protocol::parser::type_table::*; +use crate::protocol::parser::token_parsing::*; use super::visitor::{ STMT_BUFFER_INIT_CAPACITY, EXPR_BUFFER_INIT_CAPACITY, @@ -147,15 +148,16 @@ impl InferenceTypePart { // TODO: @float use InferenceTypePart as ITP; match self { - ITP::Byte | ITP::Short | ITP::Int | ITP::Long => true, + ITP::UInt8 | ITP::UInt16 | ITP::UInt32 | ITP::UInt64 | + ITP::SInt8 | ITP::SInt16 | ITP::SInt32 | ITP::SInt64 => true, _ => false, } } fn is_concrete_integer(&self) -> bool { use InferenceTypePart as ITP; - match self { - ITP::Byte | ITP::Short | ITP::Int | ITP::Long => true, + match self {ITP::UInt8 | ITP::UInt16 | ITP::UInt32 | ITP::UInt64 | + ITP::SInt8 | ITP::SInt16 | ITP::SInt32 | ITP::SInt64 => true, _ => false, } } @@ -196,8 +198,9 @@ impl InferenceTypePart { match &self { ITP::Unknown | ITP::NumberLike | ITP::IntegerLike | ITP::Void | ITP::Bool | - ITP::Byte | ITP::Short | ITP::Int | ITP::Long | - ITP::String => { + ITP::UInt8 | ITP::UInt16 | ITP::UInt32 | ITP::UInt64 | + ITP::SInt8 | ITP::SInt16 | ITP::SInt32 | ITP::SInt64 | + ITP::Character | ITP::String => { -1 }, ITP::MarkerDefinition(_) | ITP::MarkerBody(_) | @@ -225,10 +228,15 @@ impl From for InferenceTypePart { CTP::Void => ITP::Void, CTP::Message => ITP::Message, CTP::Bool => ITP::Bool, - CTP::Byte => ITP::Byte, - CTP::Short => ITP::Short, - CTP::Int => ITP::Int, - CTP::Long => ITP::Long, + CTP::UInt8 => ITP::UInt8, + CTP::UInt16 => ITP::UInt16, + CTP::UInt32 => ITP::UInt32, + CTP::UInt64 => ITP::UInt64, + CTP::SInt8 => ITP::SInt8, + CTP::SInt16 => ITP::SInt16, + CTP::SInt32 => ITP::SInt32, + CTP::SInt64 => ITP::SInt64, + CTP::Character => ITP::Character, CTP::String => ITP::String, CTP::Array => ITP::Array, CTP::Slice => ITP::Slice, @@ -635,10 +643,15 @@ impl InferenceType { ITP::Void => CTP::Void, ITP::Message => CTP::Message, ITP::Bool => CTP::Bool, - ITP::Byte => CTP::Byte, - ITP::Short => CTP::Short, - ITP::Int => CTP::Int, - ITP::Long => CTP::Long, + ITP::UInt8 => CTP::UInt8, + ITP::UInt16 => CTP::UInt16, + ITP::UInt32 => CTP::UInt32, + ITP::UInt64 => CTP::UInt64, + ITP::SInt8 => CTP::SInt8, + ITP::SInt16 => CTP::SInt16, + ITP::SInt32 => CTP::SInt32, + ITP::SInt64 => CTP::SInt64, + ITP::Character => CTP::Character, ITP::String => CTP::String, ITP::Array => CTP::Array, ITP::Slice => CTP::Slice, @@ -669,26 +682,32 @@ impl InferenceType { idx = Self::write_display_name(buffer, heap, parts, idx + 1); }, ITP::Unknown => buffer.push_str("?"), - ITP::NumberLike => buffer.push_str("num?"), - ITP::IntegerLike => buffer.push_str("int?"), + ITP::NumberLike => buffer.push_str("numberlike"), + ITP::IntegerLike => buffer.push_str("integerlike"), ITP::ArrayLike => { idx = Self::write_display_name(buffer, heap, parts, idx + 1); buffer.push_str("[?]"); }, ITP::PortLike => { - buffer.push_str("port?<"); + buffer.push_str("portlike<"); idx = Self::write_display_name(buffer, heap, parts, idx + 1); buffer.push('>'); } ITP::Void => buffer.push_str("void"), - ITP::Bool => buffer.push_str("bool"), - ITP::Byte => buffer.push_str("byte"), - ITP::Short => buffer.push_str("short"), - ITP::Int => buffer.push_str("int"), - ITP::Long => buffer.push_str("long"), - ITP::String => buffer.push_str("str"), + ITP::Bool => buffer.push_str(KW_TYPE_BOOL_STR), + ITP::UInt8 => buffer.push_str(KW_TYPE_UINT8_STR), + ITP::UInt16 => buffer.push_str(KW_TYPE_UINT16_STR), + ITP::UInt32 => buffer.push_str(KW_TYPE_UINT32_STR), + ITP::UInt64 => buffer.push_str(KW_TYPE_UINT64_STR), + ITP::SInt8 => buffer.push_str(KW_TYPE_SINT8_STR), + ITP::SInt16 => buffer.push_str(KW_TYPE_SINT16_STR), + ITP::SInt32 => buffer.push_str(KW_TYPE_SINT32_STR), + ITP::SInt64 => buffer.push_str(KW_TYPE_SINT64_STR), + ITP::Character => buffer.push_str(KW_TYPE_CHAR_STR), + ITP::String => buffer.push_str(KW_TYPE_STRING_STR), ITP::Message => { - buffer.push_str("msg<"); + buffer.push_str(KW_TYPE_MESSAGE_STR); + buffer.push('<'); idx = Self::write_display_name(buffer, heap, parts, idx + 1); buffer.push('>'); }, @@ -701,12 +720,14 @@ impl InferenceType { buffer.push_str("[..]"); }, ITP::Input => { - buffer.push_str("in<"); + buffer.push_str(KW_TYPE_IN_PORT_STR); + buffer.push('<'); idx = Self::write_display_name(buffer, heap, parts, idx + 1); buffer.push('>'); }, ITP::Output => { - buffer.push_str("out<"); + buffer.push_str(KW_TYPE_OUT_PORT_STR); + buffer.push('<'); idx = Self::write_display_name(buffer, heap, parts, idx + 1); buffer.push('>'); }, @@ -884,7 +905,7 @@ impl VarData { impl PassTyping { pub(crate) fn new() -> Self { PassTyping { - definition_type: DefinitionType::None, + definition_type: DefinitionType::Function(FunctionDefinitionId::new_invalid()), poly_vars: Vec::new(), stmt_buffer: Vec::with_capacity(STMT_BUFFER_INIT_CAPACITY), expr_buffer: Vec::with_capacity(EXPR_BUFFER_INIT_CAPACITY), @@ -943,7 +964,7 @@ impl PassTyping { } fn reset(&mut self) { - self.definition_type = DefinitionType::None; + self.definition_type = DefinitionType::Function(FunctionDefinitionId::new_invalid()); self.poly_vars.clear(); self.stmt_buffer.clear(); self.expr_buffer.clear(); @@ -964,12 +985,12 @@ impl Visitor2 for PassTyping { debug_assert_eq!(comp_def.poly_vars.len(), self.poly_vars.len(), "component polyvars do not match imposed polyvars"); debug_log!("{}", "-".repeat(50)); - debug_log!("Visiting component '{}': {}", &String::from_utf8_lossy(&comp_def.identifier.value), id.0.index); + debug_log!("Visiting component '{}': {}", comp_def.identifier.value.as_str(), id.0.index); debug_log!("{}", "-".repeat(50)); for param_id in comp_def.parameters.clone() { let param = &ctx.heap[param_id]; - let var_type = self.determine_inference_type_from_parser_type(ctx, ¶m.parser_type, true); + let var_type = self.determine_inference_type_from_parser_type_elements(¶m.parser_type.elements, true); debug_assert!(var_type.is_done, "expected component arguments to be concrete types"); self.var_types.insert(param_id.upcast(), VarData::new_local(var_type)); } @@ -985,12 +1006,12 @@ impl Visitor2 for PassTyping { debug_assert_eq!(func_def.poly_vars.len(), self.poly_vars.len(), "function polyvars do not match imposed polyvars"); debug_log!("{}", "-".repeat(50)); - debug_log!("Visiting function '{}': {}", &String::from_utf8_lossy(&func_def.identifier.value), id.0.index); + debug_log!("Visiting function '{}': {}", func_def.identifier.value.as_str(), id.0.index); debug_log!("{}", "-".repeat(50)); for param_id in func_def.parameters.clone() { let param = &ctx.heap[param_id]; - let var_type = self.determine_inference_type_from_parser_type(ctx, ¶m.parser_type, true); + let var_type = self.determine_inference_type_from_parser_type_elements(¶m.parser_type.elements, true); debug_assert!(var_type.is_done, "expected function arguments to be concrete types"); self.var_types.insert(param_id.upcast(), VarData::new_local(var_type)); } @@ -1016,7 +1037,7 @@ impl Visitor2 for PassTyping { let memory_stmt = &ctx.heap[id]; let local = &ctx.heap[memory_stmt.variable]; - let var_type = self.determine_inference_type_from_parser_type(ctx, &local.parser_type, true); + let var_type = self.determine_inference_type_from_parser_type_elements(&local.parser_type.elements, true); self.var_types.insert(memory_stmt.variable.upcast(), VarData::new_local(var_type)); Ok(()) @@ -1026,11 +1047,11 @@ impl Visitor2 for PassTyping { let channel_stmt = &ctx.heap[id]; let from_local = &ctx.heap[channel_stmt.from]; - let from_var_type = self.determine_inference_type_from_parser_type(ctx, &from_local.parser_type, true); + let from_var_type = self.determine_inference_type_from_parser_type_elements(&from_local.parser_type.elements, true); self.var_types.insert(from_local.this.upcast(), VarData::new_channel(from_var_type, channel_stmt.to.upcast())); let to_local = &ctx.heap[channel_stmt.to]; - let to_var_type = self.determine_inference_type_from_parser_type(ctx, &to_local.parser_type, true); + let to_var_type = self.determine_inference_type_from_parser_type_elements(&to_local.parser_type.elements, true); self.var_types.insert(to_local.this.upcast(), VarData::new_channel(to_var_type, channel_stmt.from.upcast())); Ok(()) @@ -1079,7 +1100,8 @@ impl Visitor2 for PassTyping { fn visit_return_stmt(&mut self, ctx: &mut Ctx, id: ReturnStatementId) -> VisitorResult { let return_stmt = &ctx.heap[id]; - let expr_id = return_stmt.expression; + debug_assert_eq!(return_stmt.expressions.len(), 1); + let expr_id = return_stmt.expressions[0]; self.visit_expr(ctx, expr_id) } @@ -1328,7 +1350,6 @@ impl PassTyping { let definition_id = match &self.definition_type { DefinitionType::Component(id) => id.upcast(), DefinitionType::Function(id) => id.upcast(), - _ => unreachable!(), }; let already_checked = ctx.types.get_base_definition(&definition_id).unwrap().has_any_monomorph(); @@ -1336,7 +1357,7 @@ impl PassTyping { if !expr_type.is_done { // Auto-infer numberlike/integerlike types to a regular int if expr_type.parts.len() == 1 && expr_type.parts[0] == InferenceTypePart::IntegerLike { - expr_type.parts[0] = InferenceTypePart::Int; + expr_type.parts[0] = InferenceTypePart::SInt32; } else { let expr = &ctx.heap[*expr_id]; return Err(ParseError::new_error_at_span( @@ -1404,8 +1425,8 @@ impl PassTyping { match &ctx.heap[*expr_id] { Expression::Call(call_expr) => { // Add to type table if not yet typechecked - if let Method::Symbolic(symbolic) = &call_expr.method { - let definition_id = symbolic.definition.unwrap(); + if call_expr.method == Method::UserFunction { + let definition_id = call_expr.definition; if !ctx.types.has_monomorph(&definition_id, &monomorph_types) { let root_id = ctx.types .get_base_definition(&definition_id) @@ -1428,9 +1449,9 @@ impl PassTyping { }, Expression::Literal(lit_expr) => { let definition_id = match &lit_expr.value { - Literal::Struct(literal) => literal.definition.as_ref().unwrap(), - Literal::Enum(literal) => literal.definition.as_ref().unwrap(), - Literal::Union(literal) => literal.definition.as_ref().unwrap(), + Literal::Struct(literal) => &literal.definition, + Literal::Enum(literal) => &literal.definition, + Literal::Union(literal) => &literal.definition, _ => unreachable!("post-inference monomorph for non-struct, non-enum literal") }; if !ctx.types.has_monomorph(definition_id, &monomorph_types) { @@ -1451,7 +1472,7 @@ impl PassTyping { let id = expr.this; self.progress_assignment_expr(ctx, id) }, - Expression::Binding(expr) => { + Expression::Binding(_expr) => { unimplemented!("progress binding expression"); }, Expression::Conditional(expr) => { @@ -1955,12 +1976,12 @@ impl PassTyping { self.apply_forced_constraint(ctx, upcast_id, &BOOL_TEMPLATE)? }, Literal::Character(_) => { + self.apply_forced_constraint(ctx, upcast_id, &CHARACTER_TEMPLATE)?; todo!("check character literal type inference"); - self.apply_forced_constraint(ctx, upcast_id, &CHARACTER_TEMPLATE)? }, Literal::String(_) => { + self.apply_forced_constraint(ctx, upcast_id, &STRING_TEMPLATE)?; todo!("check string literal type inference"); - self.apply_forced_constraint(ctx, upcast_id, &STRING_TEMPLATE)? }, Literal::Struct(data) => { let extra = self.extra_data.get_mut(&upcast_id).unwrap(); @@ -2230,13 +2251,7 @@ impl PassTyping { let expr = &ctx.heap[id]; let extra = self.extra_data.get_mut(&upcast_id).unwrap(); - debug_log!("Call expr '{}': {}", match &expr.method { - Method::Create => String::from("create"), - Method::Fires => String::from("fires"), - Method::Get => String::from("get"), - Method::Put => String::from("put"), - Method::Symbolic(method) => String::from_utf8_lossy(&method.identifier.value).to_string() - },upcast_id.index); + debug_log!("Call expr '{}': {}", ctx.heap[expr.definition].identifier().value.as_str(), upcast_id.index); debug_log!(" * Before:"); debug_log!(" - Expr type: {}", self.expr_types.get(&upcast_id).unwrap().display_name(&ctx.heap)); debug_log!(" * During (inferring types from arguments and return type):"); @@ -2343,7 +2358,7 @@ impl PassTyping { let var_expr = &ctx.heap[id]; let var_id = var_expr.declaration.unwrap(); - debug_log!("Variable expr '{}': {}", &String::from_utf8_lossy(&ctx.heap[var_id].identifier().value), upcast_id.index); + debug_log!("Variable expr '{}': {}", ctx.heap[var_id].identifier().value.as_str(), upcast_id.index); debug_log!(" * Before:"); debug_log!(" - Var type: {}", self.var_types.get(&var_id).unwrap().var_type.display_name(&ctx.heap)); debug_log!(" - Expr type: {}", self.expr_types.get(&upcast_id).unwrap().display_name(&ctx.heap)); @@ -2765,8 +2780,9 @@ impl PassTyping { EP::Return(_) => // Must match the return type of the function if let DefinitionType::Function(func_id) = self.definition_type { - let return_parser_type_id = ctx.heap[func_id].return_type; - self.determine_inference_type_from_parser_type(ctx, return_parser_type_id, true) + debug_assert_eq!(ctx.heap[func_id].return_types.len(), 1); + let returned = &ctx.heap[func_id].return_types[0]; + self.determine_inference_type_from_parser_type_elements(&returned.elements, true) } else { // Cannot happen: definition always set upon body traversal // and "return" calls in components are illegal. @@ -2803,8 +2819,6 @@ impl PassTyping { fn insert_initial_call_polymorph_data( &mut self, ctx: &mut Ctx, call_id: CallExpressionId ) { - use InferenceTypePart as ITP; - // Note: the polymorph variables may be partially specified and may // contain references to the wrapping definition's (i.e. the proctype // we are currently visiting) polymorphic arguments. @@ -2816,84 +2830,50 @@ impl PassTyping { // we are calling. let call = &ctx.heap[call_id]; - // Handle the polymorphic variables themselves - let mut poly_vars = Vec::with_capacity(call.poly_args.len()); - for poly_arg_type_id in call.poly_args.clone() { // TODO: @performance - poly_vars.push(self.determine_inference_type_from_parser_type(ctx, poly_arg_type_id, true)); + // Handle the polymorphic arguments (if there are any) + let num_poly_args = call.parser_type.elements[0].variant.num_embedded(); + let mut poly_args = Vec::with_capacity(num_poly_args); + for embedded_elements in call.parser_type.iter_embedded(0) { + poly_args.push(self.determine_inference_type_from_parser_type_elements(embedded_elements, true)); } - // Handle the arguments - // TODO: @cleanup: Maybe factor this out for reuse in the validator/linker, should also - // make the code slightly more robust. - let (embedded_types, return_type) = match &call.method { - Method::Create => { - // Not polymorphic - ( - vec![InferenceType::new(false, true, vec![ITP::Int])], - InferenceType::new(false, true, vec![ITP::Message, ITP::Byte]) - ) + // Handle the arguments and return types + let definition = &ctx.heap[call.definition]; + let (parameters, returned) = match definition { + Definition::Component(definition) => { + debug_assert_eq!(poly_args.len(), definition.poly_vars.len()); + (&definition.parameters, None) }, - Method::Fires => { - // bool fires(PortLike arg) - ( - vec![InferenceType::new(true, false, vec![ITP::PortLike, ITP::MarkerBody(0), ITP::Unknown])], - InferenceType::new(false, true, vec![ITP::Bool]) - ) + Definition::Function(definition) => { + debug_assert_eq!(poly_args.len(), definition.poly_vars.len()); + (&definition.parameters, Some(&definition.return_types)) }, - Method::Get => { - // T get(input arg) - ( - vec![InferenceType::new(true, false, vec![ITP::Input, ITP::MarkerBody(0), ITP::Unknown])], - InferenceType::new(true, false, vec![ITP::MarkerBody(0), ITP::Unknown]) - ) + Definition::Struct(_) | Definition::Enum(_) | Definition::Union(_) => { + unreachable!("insert_initial_call_polymorph data for non-procedure type"); }, - Method::Put => { - // void Put(output port, T msg) - ( - vec![ - InferenceType::new(true, false, vec![ITP::Output, ITP::MarkerBody(0), ITP::Unknown]), - InferenceType::new(true, false, vec![ITP::MarkerBody(0), ITP::Unknown]) - ], - InferenceType::new(false, true, vec![ITP::Void]) - ) - } - Method::Symbolic(symbolic) => { - let definition = &ctx.heap[symbolic.definition.unwrap()]; - - match definition { - Definition::Component(definition) => { - debug_assert_eq!(poly_vars.len(), definition.poly_vars.len()); - let mut parameter_types = Vec::with_capacity(definition.parameters.len()); - for param_id in definition.parameters.clone() { - let param = &ctx.heap[param_id]; - parameter_types.push(self.determine_inference_type_from_parser_type(ctx, ¶m.parser_type, false)); - } - - (parameter_types, InferenceType::new(false, true, vec![InferenceTypePart::Void])) - }, - Definition::Function(definition) => { - debug_assert_eq!(poly_vars.len(), definition.poly_vars.len()); - let mut parameter_types = Vec::with_capacity(definition.parameters.len()); - for param_id in definition.parameters.clone() { - let param = &ctx.heap[param_id]; - parameter_types.push(self.determine_inference_type_from_parser_type(ctx, ¶m.parser_type, false)); - } + }; - debug_assert_eq!(definition.return_types.len(), 1, "multiple return types not yet implemented"); + let mut parameter_types = Vec::with_capacity(parameters.len()); + for parameter_id in parameters.clone().into_iter() { // TODO: @Performance + let param = &ctx.heap[parameter_id]; + parameter_types.push(self.determine_inference_type_from_parser_type_elements(¶m.parser_type.elements, false)); + } - let return_type = self.determine_inference_type_from_parser_type(ctx, &definition.return_types[0], false); - (parameter_types, return_type) - }, - Definition::Struct(_) | Definition::Enum(_) | Definition::Union(_) => { - unreachable!("insert initial polymorph data for struct/enum/union"); - } - } + let return_type = match returned { + None => { + // Component, so returns a "Void" + InferenceType::new(false, true, vec![InferenceTypePart::Void]) + }, + Some(returned) => { + debug_assert_eq!(returned.len(), 1); + let returned = &returned[0]; + self.determine_inference_type_from_parser_type_elements(&returned.elements, false) } }; self.extra_data.insert(call_id.upcast(), ExtraData { - poly_vars, - embedded: embedded_types, + poly_vars: poly_args, + embedded: parameter_types, returned: return_type }); } @@ -2905,35 +2885,28 @@ impl PassTyping { let literal = ctx.heap[lit_id].value.as_struct(); // Handle polymorphic arguments - let mut poly_vars = Vec::with_capacity(literal.poly_args2.len()); + let num_embedded = literal.parser_type.elements[0].variant.num_embedded(); let mut total_num_poly_parts = 0; - for poly_arg_type_id in literal.poly_args2.clone() { // TODO: @performance - let inference_type = self.determine_inference_type_from_parser_type( - ctx, poly_arg_type_id, true - ); - total_num_poly_parts += inference_type.parts.len(); - poly_vars.push(inference_type); + let mut poly_args = Vec::with_capacity(num_embedded); + + for embedded_elements in literal.parser_type.iter_embedded(0) { + let poly_type = self.determine_inference_type_from_parser_type_elements(embedded_elements, true); + total_num_poly_parts += poly_type.parts.len(); + poly_args.push(poly_type); } // Handle parser types on struct definition - let definition = &ctx.heap[literal.definition.unwrap()]; - let definition = match definition { - Definition::Struct(definition) => { - debug_assert_eq!(poly_vars.len(), definition.poly_vars.len()); - definition - }, - _ => unreachable!("definition for struct literal does not point to struct definition") - }; + let defined_type = ctx.types.get_base_definition(&literal.definition).unwrap(); + let struct_type = defined_type.definition.as_struct(); + debug_assert_eq!(poly_args.len(), defined_type.poly_vars.len()); // Note: programmer is capable of specifying fields in a struct literal // in a different order than on the definition. We take the literal- // specified order to be leading. - let mut embedded_types = Vec::with_capacity(definition.fields.len()); + let mut embedded_types = Vec::with_capacity(struct_type.fields.len()); for lit_field in literal.fields.iter() { - let def_field = &definition.fields[lit_field.field_idx]; - let inference_type = self.determine_inference_type_from_parser_type( - ctx, &def_field.parser_type, false - ); + let def_field = &struct_type.fields[lit_field.field_idx]; + let inference_type = self.determine_inference_type_from_parser_type_elements(&def_field.parser_type.elements, false); embedded_types.push(inference_type); } @@ -2942,11 +2915,11 @@ impl PassTyping { // - 1 part for definition // - N_poly_arg marker parts for each polymorphic argument // - all the parts for the currently known polymorphic arguments - let parts_reserved = 1 + poly_vars.len() + total_num_poly_parts; + let parts_reserved = 1 + poly_args.len() + total_num_poly_parts; let mut parts = Vec::with_capacity(parts_reserved); - parts.push(ITP::Instance(definition.this.upcast(), poly_vars.len())); + parts.push(ITP::Instance(literal.definition, poly_args.len())); let mut return_type_done = true; - for (poly_var_idx, poly_var) in poly_vars.iter().enumerate() { + for (poly_var_idx, poly_var) in poly_args.iter().enumerate() { if !poly_var.is_done { return_type_done = false; } parts.push(ITP::MarkerBody(poly_var_idx)); @@ -2954,10 +2927,10 @@ impl PassTyping { } debug_assert_eq!(parts.len(), parts_reserved); - let return_type = InferenceType::new(!poly_vars.is_empty(), return_type_done, parts); + let return_type = InferenceType::new(!poly_args.is_empty(), return_type_done, parts); self.extra_data.insert(lit_id.upcast(), ExtraData{ - poly_vars, + poly_vars: poly_args, embedded: embedded_types, returned: return_type, }); @@ -2973,22 +2946,22 @@ impl PassTyping { let literal = ctx.heap[lit_id].value.as_enum(); // Handle polymorphic arguments to the enum - let mut poly_vars = Vec::with_capacity(literal.poly_args2.len()); + let num_poly_args = literal.parser_type.elements[0].variant.num_embedded(); let mut total_num_poly_parts = 0; - for poly_arg_type_id in literal.poly_args2.clone() { // TODO: @performance - let inference_type = self.determine_inference_type_from_parser_type( - ctx, poly_arg_type_id, true - ); - total_num_poly_parts += inference_type.parts.len(); - poly_vars.push(inference_type); + let mut poly_args = Vec::with_capacity(num_poly_args); + + for embedded_elements in literal.parser_type.iter_embedded(0) { + let poly_type = self.determine_inference_type_from_parser_type_elements(embedded_elements, true); + total_num_poly_parts += poly_type.parts.len(); + poly_args.push(poly_type); } // Handle enum type itself - let parts_reserved = 1 + poly_vars.len() + total_num_poly_parts; + let parts_reserved = 1 + poly_args.len() + total_num_poly_parts; let mut parts = Vec::with_capacity(parts_reserved); - parts.push(ITP::Instance(literal.definition.unwrap(), poly_vars.len())); + parts.push(ITP::Instance(literal.definition, poly_args.len())); let mut enum_type_done = true; - for (poly_var_idx, poly_var) in poly_vars.iter().enumerate() { + for (poly_var_idx, poly_var) in poly_args.iter().enumerate() { if !poly_var.is_done { enum_type_done = false; } parts.push(ITP::MarkerBody(poly_var_idx)); @@ -2996,10 +2969,10 @@ impl PassTyping { } debug_assert_eq!(parts.len(), parts_reserved); - let enum_type = InferenceType::new(!poly_vars.is_empty(), enum_type_done, parts); + let enum_type = InferenceType::new(!poly_args.is_empty(), enum_type_done, parts); self.extra_data.insert(lit_id.upcast(), ExtraData{ - poly_vars, + poly_vars: poly_args, embedded: Vec::new(), returned: enum_type, }); @@ -3014,50 +2987,48 @@ impl PassTyping { let literal = ctx.heap[lit_id].value.as_union(); // Construct the polymorphic variables - let mut poly_vars = Vec::with_capacity(literal.poly_args2.len()); + let num_poly_args = literal.parser_type.elements[0].variant.num_embedded(); let mut total_num_poly_parts = 0; - for poly_arg_type_id in literal.poly_args2.clone() { // TODO: @performance - let inference_type = self.determine_inference_type_from_parser_type( - ctx, poly_arg_type_id, true - ); - total_num_poly_parts += inference_type.parts.len(); - poly_vars.push(inference_type); + let mut poly_args = Vec::with_capacity(num_poly_args); + + for embedded_elements in literal.parser_type.iter_embedded(0) { + let poly_type = self.determine_inference_type_from_parser_type_elements(embedded_elements, true); + total_num_poly_parts += poly_type.parts.len(); + poly_args.push(poly_type); } // Handle any of the embedded values in the variant, if specified - let definition_id = literal.definition.unwrap(); - let union_definition = ctx.types.get_base_definition(&definition_id) - .unwrap() - .definition.as_union(); + let definition_id = literal.definition; + let type_definition = ctx.types.get_base_definition(&definition_id).unwrap(); + let union_definition = type_definition.definition.as_union(); + debug_assert_eq!(poly_args.len(), type_definition.poly_vars.len()); + let variant_definition = &union_definition.variants[literal.variant_idx]; debug_assert_eq!(variant_definition.embedded.len(), literal.values.len()); let mut embedded = Vec::with_capacity(variant_definition.embedded.len()); for embedded_parser_type in &variant_definition.embedded { - let inference_type = self.determine_inference_type_from_parser_type( - ctx, embedded_parser_type, false - ); + let inference_type = self.determine_inference_type_from_parser_type_elements(&embedded_parser_type.elements, false); embedded.push(inference_type); } // Handle the type of the union itself - let parts_reserved = 1 + poly_vars.len() + total_num_poly_parts; + let parts_reserved = 1 + poly_args.len() + total_num_poly_parts; let mut parts = Vec::with_capacity(parts_reserved); - parts.push(ITP::Instance(definition_id, poly_vars.len())); + parts.push(ITP::Instance(definition_id, poly_args.len())); let mut union_type_done = true; - for (poly_var_idx, poly_var) in poly_vars.iter().enumerate() { + for (poly_var_idx, poly_var) in poly_args.iter().enumerate() { if !poly_var.is_done { union_type_done = false; } parts.push(ITP::MarkerBody(poly_var_idx)); - parts.extend(poly_var.parts.iter().cloned()); } debug_assert_eq!(parts_reserved, parts.len()); - let union_type = InferenceType::new(!poly_vars.is_empty(), union_type_done, parts); + let union_type = InferenceType::new(!poly_args.is_empty(), union_type_done, parts); self.extra_data.insert(lit_id.upcast(), ExtraData{ - poly_vars, + poly_vars: poly_args, embedded, returned: union_type }); @@ -3079,6 +3050,7 @@ impl PassTyping { let field_idx = field.field_idx; // Generate initial polyvar types and struct type + // TODO: @Performance: we can immediately set the polyvars of the subject's struct type let num_poly_vars = definition.poly_vars.len(); let mut poly_vars = Vec::with_capacity(num_poly_vars); let struct_parts_reserved = 1 + 2 * num_poly_vars; @@ -3095,10 +3067,7 @@ impl PassTyping { debug_assert_eq!(struct_parts.len(), struct_parts_reserved); // Generate initial field type - let field_type = self.determine_inference_type_from_parser_type( - ctx, &definition.fields[field_idx].parser_type, false - ); - + let field_type = self.determine_inference_type_from_parser_type_elements(&definition.fields[field_idx].parser_type.elements, false); self.extra_data.insert(select_id.upcast(), ExtraData{ poly_vars, embedded: vec![InferenceType::new(num_poly_vars != 0, num_poly_vars == 0, struct_parts)], @@ -3118,18 +3087,18 @@ impl PassTyping { /// variables in the called/instantiated type's definition. /// In the second case we place InferenceTypePart::Marker instances such /// that we can perform type inference on the polymorphic variables. - fn determine_inference_type_from_parser_type( - &mut self, ctx: &Ctx, parser_type: &ParserType, + fn determine_inference_type_from_parser_type_elements( + &mut self, elements: &[ParserTypeElement], parser_type_in_body: bool ) -> InferenceType { use ParserTypeVariant as PTV; use InferenceTypePart as ITP; - let mut infer_type = Vec::with_capacity(parser_type.elements.len()); + let mut infer_type = Vec::with_capacity(elements.len()); let mut has_inferred = false; let mut has_markers = false; - for element in &parser_type.elements { + for element in elements { match &element.variant { PTV::Message => { // TODO: @types Remove the Message -> Byte hack at some point... @@ -3160,7 +3129,7 @@ impl PassTyping { if parser_type_in_body { // Refers to polymorphic argument on procedure we're currently processing. // This argument is already known. - debug_assert_eq!(belongs_to_definition, self.definition_type.definition_id()); + debug_assert_eq!(*belongs_to_definition, self.definition_type.definition_id()); debug_assert!((poly_arg_idx as usize) < self.poly_vars.len()); infer_type.push(ITP::MarkerDefinition(poly_arg_idx as usize)); @@ -3203,7 +3172,7 @@ impl PassTyping { "incompatible types: this expression expected a '{}'", expr_type.display_name(&ctx.heap) ) - ).with_postfixed_info( + ).with_info_at_span( &ctx.module.source, arg_expr.span(), format!( "but this expression yields a '{}'", arg_type.display_name(&ctx.heap) @@ -3313,9 +3282,9 @@ impl PassTyping { }, Expression::Literal(expr) => { let definition_id = match &expr.value { - Literal::Struct(v) => v.definition.unwrap(), - Literal::Enum(v) => v.definition.unwrap(), - Literal::Union(v) => v.definition.unwrap(), + Literal::Struct(v) => v.definition, + Literal::Enum(v) => v.definition, + Literal::Union(v) => v.definition, _ => unreachable!(), }; @@ -3331,7 +3300,7 @@ impl PassTyping { let field = expr.field.as_symbolic(); let (poly_var, struct_name) = get_poly_var_and_definition_name(ctx, poly_var_idx, field.definition.unwrap()); return ParseError::new_error_at_span( - &ctx.module.source, expr.position(), format!( + &ctx.module.source, expr.span, format!( "Conflicting type for polymorphic variable '{}' while accessing field '{}' of '{}'", poly_var, field.identifier.value.as_str(), struct_name ) @@ -3433,7 +3402,7 @@ impl PassTyping { InferenceType::partial_display_name(&ctx.heap, section_arg) ) ) - .with_postfixed_info( + .with_info_at_span( &ctx.module.source, expr.span(), format!( "While the {} inferred it to '{}'", expr_return_name, diff --git a/src/protocol/parser/pass_validation_linking.rs b/src/protocol/parser/pass_validation_linking.rs index 2fb9c92a521d6972e6a508f249fb861b62b31fe2..0ca5b3faf3327427e4d023d04495f450c08e15a5 100644 --- a/src/protocol/parser/pass_validation_linking.rs +++ b/src/protocol/parser/pass_validation_linking.rs @@ -263,8 +263,9 @@ impl Visitor2 for PassValidationLinking { // If here then we are within a function debug_assert_eq!(self.expr_parent, ExpressionParent::None); + debug_assert_eq!(ctx.heap[id].expressions.len(), 1); self.expr_parent = ExpressionParent::Return(id); - self.visit_expr(ctx, ctx.heap[id].expression)?; + self.visit_expr(ctx, ctx.heap[id].expressions[0])?; self.expr_parent = ExpressionParent::None; Ok(()) @@ -284,8 +285,8 @@ impl Visitor2 for PassValidationLinking { let sync_stmt = &ctx.heap[self.in_sync.unwrap()]; return Err( ParseError::new_error_str_at_span(&ctx.module.source, goto_stmt.span, "goto may not escape the surrounding synchronous block") - .with_postfixed_info(&ctx.module.source, target.label.span, "this is the target of the goto statement") - .with_postfixed_info(&ctx.module.source, sync_stmt.span, "which will jump past this statement") + .with_info_str_at_span(&ctx.module.source, target.label.span, "this is the target of the goto statement") + .with_info_str_at_span(&ctx.module.source, sync_stmt.span, "which will jump past this statement") ); } @@ -481,9 +482,11 @@ impl Visitor2 for PassValidationLinking { // Find field in the struct definition let field_idx = struct_definition.fields.iter().position(|v| v.identifier == field.identifier); if field_idx.is_none() { + let field_span = field.identifier.span; + let literal = ctx.heap[id].value.as_struct(); let ast_definition = &ctx.heap[literal.definition]; return Err(ParseError::new_error_at_span( - &ctx.module.source, field.identifier.span, format!( + &ctx.module.source, field_span, format!( "This field does not exist on the struct '{}'", ast_definition.identifier().value.as_str() ) @@ -493,8 +496,8 @@ impl Visitor2 for PassValidationLinking { // Check if specified more than once if specified[field.field_idx] { - return Err(ParseError::new_error( - &ctx.module.source, field.identifier.position, + return Err(ParseError::new_error_str_at_span( + &ctx.module.source, field.identifier.span, "This field is specified more than once" )); } @@ -551,6 +554,7 @@ impl Visitor2 for PassValidationLinking { }); if variant_idx.is_none() { + let literal = ctx.heap[id].value.as_enum(); let ast_definition = ctx.heap[literal.definition].as_enum(); return Err(ParseError::new_error_at_span( &ctx.module.source, literal.parser_type.elements[0].full_span, format!( @@ -571,6 +575,7 @@ impl Visitor2 for PassValidationLinking { v.identifier == literal.variant }); if variant_idx.is_none() { + let literal = ctx.heap[id].value.as_union(); let ast_definition = ctx.heap[literal.definition].as_union(); return Err(ParseError::new_error_at_span( &ctx.module.source, literal.parser_type.elements[0].full_span, format!( @@ -586,6 +591,7 @@ impl Visitor2 for PassValidationLinking { // number of embedded values in the union variant. let union_variant = &union_definition.variants[literal.variant_idx]; if union_variant.embedded.len() != literal.values.len() { + let literal = ctx.heap[id].value.as_union(); let ast_definition = ctx.heap[literal.definition].as_union(); return Err(ParseError::new_error_at_span( &ctx.module.source, literal.parser_type.elements[0].full_span, format!( @@ -618,7 +624,7 @@ impl Visitor2 for PassValidationLinking { let expr_section = self.expression_buffer.start_section_initialized(literal); for expr_idx in 0..expr_section.len() { let expr_id = expr_section[expr_idx]; - self.expr_parent = ExpressionParent::Expression(upcast_id, expr_id as u32); + self.expr_parent = ExpressionParent::Expression(upcast_id, expr_idx as u32); self.visit_expr(ctx, expr_id)?; } @@ -703,17 +709,17 @@ impl Visitor2 for PassValidationLinking { } if expected_wrapping_new_stmt { - if self.expr_parent != ExpressionParent::New { + if !self.expr_parent.is_new() { return Err(ParseError::new_error_str_at_span( &ctx.module.source, call_expr.span, "cannot call a component, it can only be instantiated by using 'new'" )); } } else { - if self.expr_parent == ExpressionParent::New { + if self.expr_parent.is_new() { return Err(ParseError::new_error_str_at_span( &ctx.module.source, call_expr.span, - "only components can be instantiated" + "only components can be instantiated, this is a function" )); } } @@ -723,7 +729,7 @@ impl Visitor2 for PassValidationLinking { let num_expected_args = match &call_definition.definition { DefinedTypeVariant::Function(definition) => definition.arguments.len(), DefinedTypeVariant::Component(definition) => definition.arguments.len(), - v => unreachable!("encountered {:?} type in call expression", v), + v => unreachable!("encountered {} type in call expression", v.type_class()), }; let num_provided_args = call_expr.arguments.len(); @@ -828,8 +834,9 @@ impl PassValidationLinking { } Statement::Labeled(stmt) => { let stmt_id = stmt.this; + let body_id = stmt.body; self.checked_label_add(ctx, relative_pos, self.in_sync, stmt_id)?; - self.visit_statement_for_locals_labels_and_in_sync(ctx, relative_pos, stmt.body)?; + self.visit_statement_for_locals_labels_and_in_sync(ctx, relative_pos, body_id)?; }, Statement::While(stmt) => { stmt.in_sync = self.in_sync; @@ -855,10 +862,10 @@ impl PassValidationLinking { let ident = &ctx.heap[id].identifier; if let Some(symbol) = ctx.symbols.get_symbol_by_name(cur_scope, &ident.value.as_bytes()) { return Err(ParseError::new_error_str_at_span( - &ctx.module.source, symbol.variant.span_of_introduction(&ctx.heap), + &ctx.module.source, ident.span, "local variable declaration conflicts with symbol" - ).with_postfixed_info( - &ctx.module.source, symbol.position, "the conflicting symbol is introduced here" + ).with_info_str_at_span( + &ctx.module.source, symbol.variant.span_of_introduction(&ctx.heap), "the conflicting symbol is introduced here" )); } } @@ -885,8 +892,11 @@ impl PassValidationLinking { local.identifier == other_local.identifier { // Collision within this scope return Err( - ParseError::new_error(&ctx.module.source, local.position, "Local variable name conflicts with another variable") - .with_postfixed_info(&ctx.module.source, other_local.position, "Previous variable is found here") + ParseError::new_error_str_at_span( + &ctx.module.source, local.identifier.span, "Local variable name conflicts with another variable" + ).with_info_str_at_span( + &ctx.module.source, other_local.identifier.span, "Previous variable is found here" + ) ); } } @@ -900,8 +910,11 @@ impl PassValidationLinking { let parameter = &ctx.heap[*parameter_id]; if local.identifier == parameter.identifier { return Err( - ParseError::new_error(&ctx.module.source, local.position, "Local variable name conflicts with parameter") - .with_postfixed_info(&ctx.module.source, parameter.position, "Parameter definition is found here") + ParseError::new_error_str_at_span( + &ctx.module.source, local.identifier.span, "Local variable name conflicts with parameter" + ).with_info_str_at_span( + &ctx.module.source, parameter.span, "Parameter definition is found here" + ) ); } } @@ -937,7 +950,7 @@ impl PassValidationLinking { for local_id in &block.locals { let local = &ctx.heap[*local_id]; - if local.relative_pos_in_block < relative_pos && identifier.matches_identifier(&local.identifier) { + if local.relative_pos_in_block < relative_pos && identifier == &local.identifier { return Ok(local_id.upcast()); } } @@ -951,7 +964,7 @@ impl PassValidationLinking { let definition = &ctx.heap[*definition_id]; for parameter_id in definition.parameters() { let parameter = &ctx.heap[*parameter_id]; - if identifier.matches_identifier(¶meter.identifier) { + if identifier == ¶meter.identifier { return Ok(parameter_id.upcast()); } } @@ -980,7 +993,7 @@ impl PassValidationLinking { label.relative_pos_in_block = relative_pos; label.in_sync = in_sync; - let label = &*label; + let label = &ctx.heap[id]; let mut scope = self.cur_scope.as_ref().unwrap(); loop { @@ -992,7 +1005,7 @@ impl PassValidationLinking { // Collision return Err(ParseError::new_error_str_at_span( &ctx.module.source, label.label.span, "label name is used more than once" - ).with_postfixed_info( + ).with_info_str_at_span( &ctx.module.source, other_label.label.span, "the other label is found here" )); } @@ -1036,8 +1049,8 @@ impl PassValidationLinking { if local.relative_pos_in_block > relative_scope_pos && local.relative_pos_in_block < label.relative_pos_in_block { return Err( ParseError::new_error_str_at_span(&ctx.module.source, identifier.span, "this target label skips over a variable declaration") - .with_postfixed_info(&ctx.module.source, label.label.span, "because it jumps to this label") - .with_postfixed_info(&ctx.module.source, local.identifier.span, "which skips over this variable") + .with_info_str_at_span(&ctx.module.source, label.label.span, "because it jumps to this label") + .with_info_str_at_span(&ctx.module.source, local.identifier.span, "which skips over this variable") ); } } @@ -1065,7 +1078,7 @@ impl PassValidationLinking { loop { debug_assert!(scope.is_block()); let block = scope.to_block(); - if while_stmt.body == block.upcast() { + if while_stmt.body == block { return true; } diff --git a/src/protocol/parser/symbol_table.rs b/src/protocol/parser/symbol_table.rs index 3ae3b9c9d8175b41c6bd71ab01a784eacb90430c..3ccccbf39484153d2908a57e5adf0d62fd694749 100644 --- a/src/protocol/parser/symbol_table.rs +++ b/src/protocol/parser/symbol_table.rs @@ -126,23 +126,9 @@ impl SymbolVariant { } } - pub(crate) fn as_module(&self) -> &SymbolModule { - match self { - SymbolVariant::Module(v) => v, - SymbolVariant::Definition(_) => unreachable!("called 'as_module' on {:?}", self), - } - } - pub(crate) fn as_definition(&self) -> &SymbolDefinition { match self { - SymbolVariant::Module(v) => unreachable!("called 'as_definition' on {:?}", self), - SymbolVariant::Definition(v) => v, - } - } - - pub(crate) fn as_definition_mut(&mut self) -> &mut SymbolDefinition { - match self { - SymbolVariant::Module(v) => unreachable!("called 'as_definition_mut' on {:?}", self), + SymbolVariant::Module(_) => unreachable!("called 'as_definition' on {:?}", self), SymbolVariant::Definition(v) => v, } } @@ -223,14 +209,15 @@ impl SymbolTable { /// exist in the scope or any of its parents. If it does collide then the /// symbol will be returned, together with the symbol that has the same /// name. - pub(crate) fn insert_symbol(&mut self, in_scope: SymbolScope, symbol: Symbol) -> Result<(), (Symbol, &Symbol)> { + // Note: we do not return a reference because Rust doesn't like it. + pub(crate) fn insert_symbol(&mut self, in_scope: SymbolScope, symbol: Symbol) -> Result<(), (Symbol, Symbol)> { debug_assert!(self.scope_lookup.contains_key(&in_scope), "inserting symbol {}, but scope {:?} does not exist", symbol.name.as_str(), in_scope); let mut seek_scope = in_scope; loop { let scoped_symbols = self.scope_lookup.get(&seek_scope).unwrap(); for existing_symbol in scoped_symbols.symbols.iter() { if symbol.name == existing_symbol.name { - return Err((symbol, existing_symbol)) + return Err((symbol, existing_symbol.clone())) } } diff --git a/src/protocol/parser/token_parsing.rs b/src/protocol/parser/token_parsing.rs index aa47f857aa13f709e8cbe537cb2e7775cf315c5f..ebaaefde18b5870d0dc6a577ca1091a506896ecd 100644 --- a/src/protocol/parser/token_parsing.rs +++ b/src/protocol/parser/token_parsing.rs @@ -1,4 +1,4 @@ -use crate::collections::{StringRef, ScopedSection}; +use crate::collections::ScopedSection; use crate::protocol::ast::*; use crate::protocol::input_source::{ InputSource as InputSource, @@ -8,7 +8,7 @@ use crate::protocol::input_source::{ }; use super::tokens::*; use super::symbol_table::*; -use super::{Module, ModuleCompilationPhase, PassCtx}; +use super::{Module, PassCtx}; // Keywords pub(crate) const KW_LET: &'static [u8] = b"let"; @@ -47,21 +47,39 @@ pub(crate) const KW_STMT_SYNC: &'static [u8] = b"synchronous"; pub(crate) const KW_STMT_NEW: &'static [u8] = b"new"; // Keywords - types -pub(crate) const KW_TYPE_IN_PORT: &'static [u8] = b"in"; -pub(crate) const KW_TYPE_OUT_PORT: &'static [u8] = b"out"; -pub(crate) const KW_TYPE_MESSAGE: &'static [u8] = b"msg"; -pub(crate) const KW_TYPE_BOOL: &'static [u8] = b"bool"; -pub(crate) const KW_TYPE_UINT8: &'static [u8] = b"u8"; -pub(crate) const KW_TYPE_UINT16: &'static [u8] = b"u16"; -pub(crate) const KW_TYPE_UINT32: &'static [u8] = b"u32"; -pub(crate) const KW_TYPE_UINT64: &'static [u8] = b"u64"; -pub(crate) const KW_TYPE_SINT8: &'static [u8] = b"s8"; -pub(crate) const KW_TYPE_SINT16: &'static [u8] = b"s16"; -pub(crate) const KW_TYPE_SINT32: &'static [u8] = b"s32"; -pub(crate) const KW_TYPE_SINT64: &'static [u8] = b"s64"; -pub(crate) const KW_TYPE_CHAR: &'static [u8] = b"char"; -pub(crate) const KW_TYPE_STRING: &'static [u8] = b"string"; -pub(crate) const KW_TYPE_INFERRED: &'static [u8] = b"auto"; +// Since types are needed for returning diagnostic information to the user, the +// string variants are put here as well. +pub(crate) const KW_TYPE_IN_PORT_STR: &'static str = "in"; +pub(crate) const KW_TYPE_OUT_PORT_STR: &'static str = "out"; +pub(crate) const KW_TYPE_MESSAGE_STR: &'static str = "msg"; +pub(crate) const KW_TYPE_BOOL_STR: &'static str = "bool"; +pub(crate) const KW_TYPE_UINT8_STR: &'static str = "u8"; +pub(crate) const KW_TYPE_UINT16_STR: &'static str = "u16"; +pub(crate) const KW_TYPE_UINT32_STR: &'static str = "u32"; +pub(crate) const KW_TYPE_UINT64_STR: &'static str = "u64"; +pub(crate) const KW_TYPE_SINT8_STR: &'static str = "s8"; +pub(crate) const KW_TYPE_SINT16_STR: &'static str = "s16"; +pub(crate) const KW_TYPE_SINT32_STR: &'static str = "s32"; +pub(crate) const KW_TYPE_SINT64_STR: &'static str = "s64"; +pub(crate) const KW_TYPE_CHAR_STR: &'static str = "char"; +pub(crate) const KW_TYPE_STRING_STR: &'static str = "string"; +pub(crate) const KW_TYPE_INFERRED_STR: &'static str = "auto"; + +pub(crate) const KW_TYPE_IN_PORT: &'static [u8] = KW_TYPE_IN_PORT_STR.as_bytes(); +pub(crate) const KW_TYPE_OUT_PORT: &'static [u8] = KW_TYPE_OUT_PORT_STR.as_bytes(); +pub(crate) const KW_TYPE_MESSAGE: &'static [u8] = KW_TYPE_MESSAGE_STR.as_bytes(); +pub(crate) const KW_TYPE_BOOL: &'static [u8] = KW_TYPE_BOOL_STR.as_bytes(); +pub(crate) const KW_TYPE_UINT8: &'static [u8] = KW_TYPE_UINT8_STR.as_bytes(); +pub(crate) const KW_TYPE_UINT16: &'static [u8] = KW_TYPE_UINT16_STR.as_bytes(); +pub(crate) const KW_TYPE_UINT32: &'static [u8] = KW_TYPE_UINT32_STR.as_bytes(); +pub(crate) const KW_TYPE_UINT64: &'static [u8] = KW_TYPE_UINT64_STR.as_bytes(); +pub(crate) const KW_TYPE_SINT8: &'static [u8] = KW_TYPE_SINT8_STR.as_bytes(); +pub(crate) const KW_TYPE_SINT16: &'static [u8] = KW_TYPE_SINT16_STR.as_bytes(); +pub(crate) const KW_TYPE_SINT32: &'static [u8] = KW_TYPE_SINT32_STR.as_bytes(); +pub(crate) const KW_TYPE_SINT64: &'static [u8] = KW_TYPE_SINT64_STR.as_bytes(); +pub(crate) const KW_TYPE_CHAR: &'static [u8] = KW_TYPE_CHAR_STR.as_bytes(); +pub(crate) const KW_TYPE_STRING: &'static [u8] = KW_TYPE_STRING_STR.as_bytes(); +pub(crate) const KW_TYPE_INFERRED: &'static [u8] = KW_TYPE_INFERRED_STR.as_bytes(); /// A special trait for when consuming comma-separated things such that we can /// push them onto a `Vec` and onto a `ScopedSection`. As we monomorph for @@ -82,7 +100,7 @@ impl Extendable for Vec { } } -impl Extendable for ScopedSection { +impl Extendable for ScopedSection { type Value = T; #[inline] @@ -136,11 +154,11 @@ pub(crate) fn consume_token(source: &InputSource, iter: &mut TokenIter, expected /// Consumes a comma separated list until the closing delimiter is encountered pub(crate) fn consume_comma_separated_until( - close_delim: TokenKind, source: &InputSource, iter: &mut TokenIter, - consumer_fn: F, target: &mut E, item_name_and_article: &'static str, + close_delim: TokenKind, source: &InputSource, iter: &mut TokenIter, ctx: &mut PassCtx, + mut consumer_fn: F, target: &mut E, item_name_and_article: &'static str, close_pos: Option<&mut InputPosition> ) -> Result<(), ParseError> - where F: Fn(&InputSource, &mut TokenIter) -> Result, + where F: FnMut(&InputSource, &mut TokenIter, &mut PassCtx) -> Result, E: Extendable { let mut had_comma = true; @@ -162,7 +180,7 @@ pub(crate) fn consume_comma_separated_until( )); } - let new_item = consumer_fn(source, iter)?; + let new_item = consumer_fn(source, iter, ctx)?; target.push(new_item); next = iter.next(); @@ -183,28 +201,28 @@ pub(crate) fn consume_comma_separated_until( /// - Opening and closing delimiter encountered, and items were processed. /// - Found an opening delimiter, but processing an item failed. pub(crate) fn maybe_consume_comma_separated( - open_delim: TokenKind, close_delim: TokenKind, source: &InputSource, iter: &mut TokenIter, + open_delim: TokenKind, close_delim: TokenKind, source: &InputSource, iter: &mut TokenIter, ctx: &mut PassCtx, consumer_fn: F, target: &mut E, item_name_and_article: &'static str, close_pos: Option<&mut InputPosition> ) -> Result - where F: Fn(&InputSource, &mut TokenIter) -> Result, + where F: FnMut(&InputSource, &mut TokenIter, &mut PassCtx) -> Result, E: Extendable { - let mut next = iter.next(); - if Some(open_delim) != next { + if Some(open_delim) != iter.next() { return Ok(false); } // Opening delimiter encountered, so must parse the comma-separated list. iter.consume(); - consume_comma_separated_until(close_delim, source, iter, consumer_fn, target, item_name_and_article, close_pos)?; + consume_comma_separated_until(close_delim, source, iter, ctx, consumer_fn, target, item_name_and_article, close_pos)?; Ok(true) } -pub(crate) fn maybe_consume_comma_separated_spilled Result<(), ParseError>>( - open_delim: TokenKind, close_delim: TokenKind, source: &InputSource, iter: &mut TokenIter, - consumer_fn: F, item_name_and_article: &'static str +pub(crate) fn maybe_consume_comma_separated_spilled Result<(), ParseError>>( + open_delim: TokenKind, close_delim: TokenKind, source: &InputSource, + iter: &mut TokenIter, ctx: &mut PassCtx, + mut consumer_fn: F, item_name_and_article: &'static str ) -> Result { let mut next = iter.next(); if Some(open_delim) != next { @@ -225,7 +243,7 @@ pub(crate) fn maybe_consume_comma_separated_spilled( - open_delim: TokenKind, close_delim: TokenKind, source: &InputSource, iter: &mut TokenIter, + open_delim: TokenKind, close_delim: TokenKind, source: &InputSource, + iter: &mut TokenIter, ctx: &mut PassCtx, consumer_fn: F, target: &mut E, item_name_and_article: &'static str, list_name_and_article: &'static str, close_pos: Option<&mut InputPosition> ) -> Result<(), ParseError> - where F: Fn(&InputSource, &mut TokenIter) -> Result, + where F: FnMut(&InputSource, &mut TokenIter, &mut PassCtx) -> Result, E: Extendable { let first_pos = iter.last_valid_pos(); match maybe_consume_comma_separated( - open_delim, close_delim, source, iter, consumer_fn, target, + open_delim, close_delim, source, iter, ctx, consumer_fn, target, item_name_and_article, close_pos ) { Ok(true) => Ok(()), diff --git a/src/protocol/parser/tokens.rs b/src/protocol/parser/tokens.rs index 8e57871340a7d2f36840b621bde96b42435fb388..d1ae773a037be730c655cd3b4585542f6a73723b 100644 --- a/src/protocol/parser/tokens.rs +++ b/src/protocol/parser/tokens.rs @@ -7,7 +7,7 @@ use crate::protocol::input_source::{ /// variable-character tokens. Such a token is always followed by a /// `TokenKind::SpanEnd` token. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub(crate) enum TokenKind { +pub enum TokenKind { // Variable-character tokens, followed by a SpanEnd token Ident, // regular identifier Pragma, // identifier with prefixed `#`, range includes `#` @@ -32,8 +32,6 @@ pub(crate) enum TokenKind { Comma, // , Dot, // . SemiColon, // ; - Quote, // ' - DoubleQuote, // " // Operator-like (single character) At, // @ Plus, // + @@ -117,8 +115,6 @@ impl TokenKind { TK::Comma => ",", TK::Dot => ".", TK::SemiColon => ";", - TK::Quote => "'", - TK::DoubleQuote => "\"", TK::At => "@", TK::Plus => "+", TK::Minus => "-", @@ -161,7 +157,7 @@ impl TokenKind { } /// Represents a single token at a particular position. -pub(crate) struct Token { +pub struct Token { pub kind: TokenKind, pub pos: InputPosition, } @@ -173,8 +169,8 @@ impl Token { } /// The kind of token ranges that are specially parsed by the tokenizer. -#[derive(Debug, PartialEq, Eq)] -pub(crate) enum TokenRangeKind { +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum TokenRangeKind { Module, Pragma, Import, @@ -185,7 +181,7 @@ pub(crate) enum TokenRangeKind { /// A range of tokens with a specific meaning. Such a range is part of a tree /// where each parent tree envelops all of its children. #[derive(Debug)] -pub(crate) struct TokenRange { +pub struct TokenRange { // Index of parent in `TokenBuffer.ranges`, does not have a parent if the // range kind is Module, in that case the parent index points to itself. pub parent_idx: usize, @@ -201,7 +197,7 @@ pub(crate) struct TokenRange { pub next_sibling_idx: Option, } -pub(crate) struct TokenBuffer { +pub struct TokenBuffer { pub tokens: Vec, pub ranges: Vec, } diff --git a/src/protocol/parser/type_table.rs b/src/protocol/parser/type_table.rs index 2ad628bd6c54fa41baf3f9eb84c7f1961ccd38ac..9fc2f5e87b61020ef6da904e2b4c7f8a7b9aaa4d 100644 --- a/src/protocol/parser/type_table.rs +++ b/src/protocol/parser/type_table.rs @@ -29,14 +29,6 @@ impl TypeClass { TypeClass::Component => "component", } } - - pub(crate) fn is_data_type(&self) -> bool { - *self == TypeClass::Enum || *self == TypeClass::Union || *self == TypeClass::Struct - } - - pub(crate) fn is_proc_type(&self) -> bool { - *self == TypeClass::Function || *self == TypeClass::Component - } } impl std::fmt::Display for TypeClass { @@ -58,7 +50,6 @@ pub struct DefinedType { pub(crate) definition: DefinedTypeVariant, pub(crate) poly_vars: Vec, pub(crate) is_polymorph: bool, - pub(crate) is_pointerlike: bool, // TODO: @optimize pub(crate) monomorphs: Vec>, } @@ -124,7 +115,7 @@ impl DefinedTypeVariant { } } -struct PolymorphicVariable { +pub struct PolymorphicVariable { identifier: Identifier, is_in_use: bool, // a polymorphic argument may be defined, but not used by the type definition } @@ -411,7 +402,6 @@ impl TypeTable { }), poly_vars, is_polymorph: false, - is_pointerlike: false, monomorphs: Vec::new() }); @@ -490,7 +480,6 @@ impl TypeTable { }), poly_vars, is_polymorph, - is_pointerlike: false, // TODO: @cyclic_types monomorphs: Vec::new() }); @@ -545,7 +534,6 @@ impl TypeTable { }), poly_vars, is_polymorph, - is_pointerlike: false, // TODO: @cyclic monomorphs: Vec::new(), }); @@ -611,7 +599,6 @@ impl TypeTable { }), poly_vars, is_polymorph, - is_pointerlike: false, // TODO: @cyclic monomorphs: Vec::new(), }); @@ -671,7 +658,6 @@ impl TypeTable { }), poly_vars, is_polymorph, - is_pointerlike: false, // TODO: @cyclic monomorphs: Vec::new(), }); diff --git a/src/protocol/tests/utils.rs b/src/protocol/tests/utils.rs index b3758135f2ce67f881e0fb6912ff9fe436ab87b3..0cd60489e610f5f90119e2519266e18d6e059495 100644 --- a/src/protocol/tests/utils.rs +++ b/src/protocol/tests/utils.rs @@ -15,7 +15,7 @@ use crate::protocol::{ struct TestCtx<'a> { test_name: &'a str, heap: &'a Heap, - modules: &'a Vec, + modules: &'a Vec, types: &'a TypeTable, symbols: &'a SymbolTable, } @@ -63,10 +63,9 @@ impl Tester { pub(crate) fn compile(self) -> AstTesterResult { let mut parser = Parser::new(); - for (source_idx, source) in self.sources.into_iter().enumerate() { + for source in self.sources.into_iter() { let source = source.into_bytes(); - let input_source = InputSource::new(String::from(""), source) - .expect(&format!("parsing source {}", source_idx + 1)); + let input_source = InputSource::new(String::from(""), source); if let Err(err) = parser.feed(input_source) { return AstTesterResult::Err(AstErrTester::new(self.test_name, err)) @@ -120,7 +119,7 @@ impl AstTesterResult { pub(crate) struct AstOkTester { test_name: String, - modules: Vec, + modules: Vec, heap: Heap, symbols: SymbolTable, types: TypeTable, @@ -489,7 +488,7 @@ impl<'a> FunctionTester<'a> { &|expr| { if let Expression::Assignment(assign_expr) = expr { if let Expression::Variable(variable_expr) = &self.ctx.heap[assign_expr.left] { - if variable_expr.position.offset == local.identifier.position.offset { + if variable_expr.identifier.span.begin.offset == local.identifier.span.begin.offset { return true; } } @@ -533,7 +532,7 @@ impl<'a> FunctionTester<'a> { // Find the first occurrence of the expression after the definition of // the function, we'll check that it is included in the body later. - let mut outer_match_idx = self.def.position.offset; + let mut outer_match_idx = self.def.span.begin.offset as usize; while outer_match_idx < module.source.input.len() { if module.source.input[outer_match_idx..].starts_with(outer_match.as_bytes()) { break; @@ -551,7 +550,7 @@ impl<'a> FunctionTester<'a> { // Use the inner match index to find the expression let expr_id = seek_expr_in_stmt( &self.ctx.heap, self.def.body.upcast(), - &|expr| expr.position().offset == inner_match_idx + &|expr| expr.span().begin.offset as usize == inner_match_idx ); assert!( expr_id.is_some(), @@ -748,7 +747,7 @@ impl<'a> ErrorTester<'a> { self.test_name, pattern, self.assert_postfix() ); let pos = pos.unwrap(); - let col = self.error.statements[idx].position.column; + let col = self.error.statements[idx].start_column as usize; assert_eq!( pos + 1, col, "[{}] Expected error to occur at column {}, but found it at {} for {}", @@ -955,7 +954,7 @@ fn serialize_concrete_type(buffer: &mut String, heap: &Heap, def: DefinitionId, serialize_recursive(buffer, heap, poly_vars, concrete, 0); } -fn seek_def_in_modules<'a>(heap: &Heap, modules: &'a [LexedModule], def_id: DefinitionId) -> Option<&'a LexedModule> { +fn seek_def_in_modules<'a>(heap: &Heap, modules: &'a [Module], def_id: DefinitionId) -> Option<&'a Module> { for module in modules { let root = &heap.protocol_descriptions[module.root_id]; for definition in &root.definitions { @@ -1069,7 +1068,7 @@ fn seek_expr_in_expr bool>(heap: &Heap, start: ExpressionI } None }, - Expression::Variable(expr) => { + Expression::Variable(_expr) => { None } } @@ -1109,10 +1108,12 @@ fn seek_expr_in_stmt bool>(heap: &Heap, start: StatementId seek_expr_in_stmt(heap, stmt.body.upcast(), f) }, Statement::Return(stmt) => { - seek_expr_in_expr(heap, stmt.expression, f) - }, - Statement::Assert(stmt) => { - seek_expr_in_expr(heap, stmt.expression, f) + for expr_id in &stmt.expressions { + if let Some(id) = seek_expr_in_expr(heap, *expr_id, f) { + return Some(id); + } + } + None }, Statement::New(stmt) => { seek_expr_in_expr(heap, stmt.expression.upcast(), f)