diff --git a/src/protocol/ast.rs b/src/protocol/ast.rs index 468330bceee9955aaa86445979d345f962df61e9..63762b6dadd95850af6bb4b2325310725ccb67ea 100644 --- a/src/protocol/ast.rs +++ b/src/protocol/ast.rs @@ -372,6 +372,10 @@ pub enum ParserTypeVariant { Array, Input, Output, + // Tuple: expecting any number of elements. Note that the parser type can + // have one-valued tuples, these will be filtered out later during type + // checking. + Tuple(u32), // u32 = number of subsequent types // User-defined types PolymorphicArgument(DefinitionId, u32), // u32 = index into polymorphic variables Definition(DefinitionId, u32), // u32 = number of subsequent types in the type tree. @@ -391,7 +395,7 @@ impl ParserTypeVariant { 0, ArrayLike | InputOrOutput | Array | Input | Output => 1, - Definition(_, num) => *num as usize, + Definition(_, num) | Tuple(num) => *num as usize, } } } diff --git a/src/protocol/parser/mod.rs b/src/protocol/parser/mod.rs index 5da7873cd080decd8d107c3d64530e7c129a254a..935ccdcc7d7b7b3e50bc31fbeb2cef2f96d7faff 100644 --- a/src/protocol/parser/mod.rs +++ b/src/protocol/parser/mod.rs @@ -6,6 +6,7 @@ pub(crate) mod pass_tokenizer; pub(crate) mod pass_symbols; pub(crate) mod pass_imports; pub(crate) mod pass_definitions; +pub(crate) mod pass_definitions_types; pub(crate) mod pass_validation_linking; pub(crate) mod pass_typing; mod visitor; diff --git a/src/protocol/parser/pass_definitions.rs b/src/protocol/parser/pass_definitions.rs index c35967df9b31f6f355d7c5793502e07fac428c8d..5955dfdff242e285bdfef5ac867b75c9b5fcab40 100644 --- a/src/protocol/parser/pass_definitions.rs +++ b/src/protocol/parser/pass_definitions.rs @@ -460,8 +460,8 @@ impl PassDefinitions { self.consume_labeled_statement(module, iter, ctx, section)?; } else { // Two fallback possibilities: the first one is a memory - // declaration, the other one is to parse it as a regular - // expression. This is a bit ugly + // declaration, the other one is to parse it as a normal + // expression. This is a bit ugly. if let Some((memory_stmt_id, assignment_stmt_id)) = self.maybe_consume_memory_statement(module, iter, ctx)? { section.push(memory_stmt_id.upcast().upcast()); section.push(assignment_stmt_id.upcast()); @@ -1709,7 +1709,7 @@ fn consume_parser_type( depth: i32, } - // After parsing the array modified "[]", we need to insert an array type + // After parsing the array modifier "[]", we need to insert an array type // before the most recently parsed type. fn insert_array_before(elements: &mut Vec, depth: i32, span: InputSpan) { let index = elements.iter().rposition(|e| e.depth == depth).unwrap(); diff --git a/src/protocol/parser/pass_definitions_types.rs b/src/protocol/parser/pass_definitions_types.rs new file mode 100644 index 0000000000000000000000000000000000000000..a67c9f5f48d4dc486f18b7d97718ab603e6435c2 --- /dev/null +++ b/src/protocol/parser/pass_definitions_types.rs @@ -0,0 +1,125 @@ +use crate::protocol::*; +use crate::protocol::parser::*; + +struct Entry { + element: ParserTypeElement, + depth: i32, +} + +#[derive(Copy, Clone)] +enum DepthKind { + Tuple, // because we had a `(` token + PolyArgs, // because we had a `<` token +} + +struct DepthElement { + kind: DepthKind, + pos: InputPosition, +} + +/// Temporarily keep the error around in unevaluated format because sometimes +/// when we evaluate a `ParserType`, we perform some backtracking if it fails. +enum ParserTypeError { + ExpectedAType(InputPosition), + MessageAt(InputPosition, &'static str), + TwoMessageAt(InputPosition, &'static str, InputPosition, &'static str), +} + +/// Parsers tokens into `ParserType` instances (yes, the name of the struct is +/// silly). Essentially a little state machine with its own temporary storage. +pub(crate) struct ParserTypeParser { + entries: Vec, + depths: Vec, + first_pos: InputPosition, + last_pos: InputPosition, +} + +impl ParserTypeParser { + pub(crate) fn consume_parser_type( + &mut self, + source: &InputSource, iter: &mut TokenIter, + symbols: &SymbolTable, heap: &Heap, poly_vars: &[Identifier], + cur_scope: SymbolScope, wrapping_definition: DefinitionId, + allow_inference: bool, inside_angular_bracket: Option, + ) -> Result { + // Make sure we start in an empty state + debug_assert!(self.entries.is_empty()); + debug_assert!(self.depths.is_empty()); + + // Setup processing + if let Some(bracket_pos) = inside_angular_bracket { + self.push_depth(DepthKind::PolyArgs, bracket_pos); + } + + let first_element = match iter.next() { + Some(TokenKind::Ident) => { + + }, + Some(TokenKind::OpenParen) => { + let tuple_start_pos = iter.next_start_position(); + self.push_depth(DepthKind::Tuple, tuple_start_pos); + self.entries.push(Entry{ + element: ParserTypeElement{ + element_span: InputSpan::from_positions(tuple_start_pos, tuple_start_pos), + variant: ParserTypeVariant::Tuple(0), + }, + depth: self.cur_depth(), + }); + iter.consume(); + }, + _ => return Err(ParserTypeError::MessageAt(iter.last_valid_pos(), "expected a type")), + }; + + // Convert the results from parsing into the `ParserType` + let mut elements = Vec::with_capacity(self.entries.len()); + debug_assert!(!self.entries.is_empty()); + + for entry in self.entries.drain(..) { + elements.push(entry.element) + } + + return Ok(ParserType{ + elements, + full_span: InputSpan::from_positions(self.first_pos, self.last_pos), + }); + } + + /// Consumes an identifier that should resolve to some kind of type. There + /// may be trailing '::' tokens, commas, or polymorphic arguments. + fn consume_parser_type_ident( + &self, iter: &mut TokenIter, symbols: &SymbolTable, poly_vars: &[Identifier], + allow_inference: bool, + ) -> Result { + + } + + #[inline] + fn push_depth(&mut self, kind: DepthKind, pos: InputPosition) { + self.depths.push(DepthElement{ kind, pos }); + } + + #[inline] + fn pop_depth(&mut self, kind: DepthKind, pos: InputPosition) -> Result<(), ParserTypeError> { + if self.depths.is_empty() { + // More closing parens than opening ones + let message = match kind { + DepthKind::Tuple => "unmatched ')'", + DepthKind::PolyArgs => "unmatched '>'", + }; + return Err(ParserTypeError::MessageAt(pos, message)) + } + + let last = *self.depths.last().unwrap(); + if last != kind { + // Wrong kind of paren + let (message_second) = match kind { + DepthKind::Tuple => "unexpected closing" + } + } + } + + #[inline] + fn cur_depth(&self) -> i32 { + return self.depths.len() as i32; + } +} \ No newline at end of file diff --git a/src/protocol/parser/tokens.rs b/src/protocol/parser/tokens.rs index 107b6a34e08931bb5319971eb0f1f710b44cb668..ccf6982e268efdeaf5a532c9644a6803fd9d148a 100644 --- a/src/protocol/parser/tokens.rs +++ b/src/protocol/parser/tokens.rs @@ -298,6 +298,13 @@ impl<'a> TokenIter<'a> { }; } + /// Assumes the token is not at the end and returns the starting position + /// belonging to the token returned by `next`. + pub(crate) fn next_start_position(&self) -> InputPosition { + debug_assert!(self.cur < self.end); + return self.tokens[self.cur].pos; + } + /// Returns the token range belonging to the token returned by `next`. This /// assumes that we're not at the end of the range we're iterating over. pub(crate) fn next_positions(&self) -> (InputPosition, InputPosition) {