Browse Source

split the statement parsing into multiple function to make it more manageable

Tamo 1 year ago
parent
commit
c88ca1c91f
1 changed files with 373 additions and 347 deletions
  1. 373 347
      numbat/src/parser.rs

+ 373 - 347
numbat/src/parser.rs

@@ -395,447 +395,473 @@ impl<'a> Parser<'a> {
         }
 
         if self.match_exact(TokenKind::Let).is_some() {
-            if let Some(identifier) = self.match_exact(TokenKind::Identifier) {
-                let identifier_span = self.last().unwrap().span;
-
-                let type_annotation = if self.match_exact(TokenKind::Colon).is_some() {
-                    Some(self.type_annotation()?)
-                } else {
-                    None
-                };
+            self.parse_let()
+        } else if self.match_exact(TokenKind::Fn).is_some() {
+            self.parse_function_declaration()
+        } else if self.match_exact(TokenKind::Dimension).is_some() {
+            self.parse_dimension_declaration()
+        } else if self.match_exact(TokenKind::At).is_some() {
+            self.parse_decorators()
+        } else if self.match_exact(TokenKind::Unit).is_some() {
+            self.parse_unit_declaration()
+        } else if self.match_exact(TokenKind::Use).is_some() {
+            self.parse_use()
+        } else if self.match_exact(TokenKind::Struct).is_some() {
+            self.parse_struct()
+        } else if self.match_any(PROCEDURES).is_some() {
+            self.parse_procedure()
+        } else {
+            Ok(Statement::Expression(self.expression()?))
+        }
+    }
 
-                if self.match_exact(TokenKind::Equal).is_none() {
-                    Err(ParseError {
-                        kind: ParseErrorKind::ExpectedEqualOrColonAfterLetIdentifier,
-                        span: self.peek().span,
-                    })
-                } else {
-                    self.skip_empty_lines();
-                    let expr = self.expression()?;
+    fn parse_let(&mut self) -> Result<Statement> {
+        if let Some(identifier) = self.match_exact(TokenKind::Identifier) {
+            let identifier_span = self.last().unwrap().span;
 
-                    if decorator::contains_aliases_with_prefixes(&self.decorator_stack) {
-                        return Err(ParseError {
-                            kind: ParseErrorKind::DecoratorsWithPrefixOnLetDefinition,
-                            span: self.peek().span,
-                        });
-                    }
-                    let mut decorators = vec![];
-                    std::mem::swap(&mut decorators, &mut self.decorator_stack);
-
-                    Ok(Statement::DefineVariable {
-                        identifier_span,
-                        identifier: identifier.lexeme.clone(),
-                        expr,
-                        type_annotation,
-                        decorators,
-                    })
-                }
+            let type_annotation = if self.match_exact(TokenKind::Colon).is_some() {
+                Some(self.type_annotation()?)
             } else {
+                None
+            };
+
+            if self.match_exact(TokenKind::Equal).is_none() {
                 Err(ParseError {
-                    kind: ParseErrorKind::ExpectedIdentifierAfterLet,
+                    kind: ParseErrorKind::ExpectedEqualOrColonAfterLetIdentifier,
                     span: self.peek().span,
                 })
-            }
-        } else if self.match_exact(TokenKind::Fn).is_some() {
-            if let Some(fn_name) = self.match_exact(TokenKind::Identifier) {
-                let function_name_span = self.last().unwrap().span;
-                let mut type_parameters = vec![];
-                // Parsing the generic parameters if there are any
-                if self.match_exact(TokenKind::LessThan).is_some() {
-                    while self.match_exact(TokenKind::GreaterThan).is_none() {
-                        if let Some(type_parameter_name) = self.match_exact(TokenKind::Identifier) {
-                            let bound = if self.match_exact(TokenKind::Colon).is_some() {
-                                match self.match_exact(TokenKind::Identifier) {
-                                    Some(token) if token.lexeme == "Dim" => {
-                                        Some(TypeParameterBound::Dim)
-                                    }
-                                    Some(token) => {
-                                        return Err(ParseError {
-                                            kind: ParseErrorKind::UnknownBound(
-                                                token.lexeme.clone(),
-                                            ),
-                                            span: token.span,
-                                        });
-                                    }
-                                    None => {
-                                        return Err(ParseError {
-                                            kind: ParseErrorKind::ExpectedBoundInTypeParameterDefinition,
-                                            span: self.peek().span,
-                                        });
-                                    }
-                                }
-                            } else {
-                                None
-                            };
-
-                            let span = self.last().unwrap().span;
-                            type_parameters.push((
-                                span,
-                                type_parameter_name.lexeme.to_string(),
-                                bound,
-                            ));
-
-                            if self.match_exact(TokenKind::Comma).is_none()
-                                && self.peek().kind != TokenKind::GreaterThan
-                            {
-                                return Err(ParseError {
-                                    kind: ParseErrorKind::ExpectedCommaOrRightAngleBracket,
-                                    span: self.peek().span,
-                                });
-                            }
-                        } else {
-                            return Err(ParseError {
-                                kind: ParseErrorKind::ExpectedTypeParameterName,
-                                span: self.peek().span,
-                            });
-                        }
-                    }
-                }
+            } else {
+                self.skip_empty_lines();
+                let expr = self.expression()?;
 
-                if self.match_exact(TokenKind::LeftParen).is_none() {
+                if decorator::contains_aliases_with_prefixes(&self.decorator_stack) {
                     return Err(ParseError {
-                        kind: ParseErrorKind::ExpectedLeftParenInFunctionDefinition,
+                        kind: ParseErrorKind::DecoratorsWithPrefixOnLetDefinition,
                         span: self.peek().span,
                     });
                 }
+                let mut decorators = vec![];
+                std::mem::swap(&mut decorators, &mut self.decorator_stack);
 
-                let mut parameter_span = self.peek().span;
+                Ok(Statement::DefineVariable {
+                    identifier_span,
+                    identifier: identifier.lexeme.clone(),
+                    expr,
+                    type_annotation,
+                    decorators,
+                })
+            }
+        } else {
+            Err(ParseError {
+                kind: ParseErrorKind::ExpectedIdentifierAfterLet,
+                span: self.peek().span,
+            })
+        }
+    }
 
-                self.match_exact(TokenKind::Newline);
-                let mut parameters = vec![];
-                while self.match_exact(TokenKind::RightParen).is_none() {
-                    if let Some(param_name) = self.match_exact(TokenKind::Identifier) {
-                        let span = self.last().unwrap().span;
-                        let param_type_dexpr = if self.match_exact(TokenKind::Colon).is_some() {
-                            Some(self.type_annotation()?)
+    fn parse_function_declaration(&mut self) -> Result<Statement> {
+        if let Some(fn_name) = self.match_exact(TokenKind::Identifier) {
+            let function_name_span = self.last().unwrap().span;
+            let mut type_parameters = vec![];
+            // Parsing the generic parameters if there are any
+            if self.match_exact(TokenKind::LessThan).is_some() {
+                while self.match_exact(TokenKind::GreaterThan).is_none() {
+                    if let Some(type_parameter_name) = self.match_exact(TokenKind::Identifier) {
+                        let bound = if self.match_exact(TokenKind::Colon).is_some() {
+                            match self.match_exact(TokenKind::Identifier) {
+                                Some(token) if token.lexeme == "Dim" => {
+                                    Some(TypeParameterBound::Dim)
+                                }
+                                Some(token) => {
+                                    return Err(ParseError {
+                                        kind: ParseErrorKind::UnknownBound(token.lexeme.clone()),
+                                        span: token.span,
+                                    });
+                                }
+                                None => {
+                                    return Err(ParseError {
+                                        kind:
+                                            ParseErrorKind::ExpectedBoundInTypeParameterDefinition,
+                                        span: self.peek().span,
+                                    });
+                                }
+                            }
                         } else {
                             None
                         };
 
-                        parameters.push((span, param_name.lexeme.to_string(), param_type_dexpr));
-
-                        parameter_span = parameter_span.extend(&self.last().unwrap().span);
-
-                        self.skip_empty_lines();
-                        let has_comma = self.match_exact(TokenKind::Comma).is_some();
-                        self.skip_empty_lines();
-                        if self.match_exact(TokenKind::RightParen).is_some() {
-                            break;
-                        }
+                        let span = self.last().unwrap().span;
+                        type_parameters.push((span, type_parameter_name.lexeme.to_string(), bound));
 
-                        if !has_comma && self.peek().kind != TokenKind::RightParen {
+                        if self.match_exact(TokenKind::Comma).is_none()
+                            && self.peek().kind != TokenKind::GreaterThan
+                        {
                             return Err(ParseError {
-                                kind: ParseErrorKind::ExpectedCommaEllipsisOrRightParenInFunctionDefinition,
+                                kind: ParseErrorKind::ExpectedCommaOrRightAngleBracket,
                                 span: self.peek().span,
                             });
                         }
                     } else {
                         return Err(ParseError {
-                            kind: ParseErrorKind::ExpectedParameterNameInFunctionDefinition,
+                            kind: ParseErrorKind::ExpectedTypeParameterName,
                             span: self.peek().span,
                         });
                     }
                 }
+            }
 
-                let return_type_annotation = if self.match_exact(TokenKind::Arrow).is_some() {
-                    Some(self.type_annotation()?)
-                } else {
-                    None
-                };
+            if self.match_exact(TokenKind::LeftParen).is_none() {
+                return Err(ParseError {
+                    kind: ParseErrorKind::ExpectedLeftParenInFunctionDefinition,
+                    span: self.peek().span,
+                });
+            }
+
+            let mut parameter_span = self.peek().span;
+
+            self.match_exact(TokenKind::Newline);
+            let mut parameters = vec![];
+            while self.match_exact(TokenKind::RightParen).is_none() {
+                if let Some(param_name) = self.match_exact(TokenKind::Identifier) {
+                    let span = self.last().unwrap().span;
+                    let param_type_dexpr = if self.match_exact(TokenKind::Colon).is_some() {
+                        Some(self.type_annotation()?)
+                    } else {
+                        None
+                    };
+
+                    parameters.push((span, param_name.lexeme.to_string(), param_type_dexpr));
+
+                    parameter_span = parameter_span.extend(&self.last().unwrap().span);
 
-                let body = if self.match_exact(TokenKind::Equal).is_none() {
-                    None
-                } else {
                     self.skip_empty_lines();
-                    Some(self.expression()?)
-                };
+                    let has_comma = self.match_exact(TokenKind::Comma).is_some();
+                    self.skip_empty_lines();
+                    if self.match_exact(TokenKind::RightParen).is_some() {
+                        break;
+                    }
 
-                if decorator::contains_aliases(&self.decorator_stack) {
+                    if !has_comma && self.peek().kind != TokenKind::RightParen {
+                        return Err(ParseError {
+                                kind: ParseErrorKind::ExpectedCommaEllipsisOrRightParenInFunctionDefinition,
+                                span: self.peek().span,
+                            });
+                    }
+                } else {
                     return Err(ParseError {
-                        kind: ParseErrorKind::AliasUsedOnFunction,
+                        kind: ParseErrorKind::ExpectedParameterNameInFunctionDefinition,
                         span: self.peek().span,
                     });
                 }
+            }
 
-                let mut decorators = vec![];
-                std::mem::swap(&mut decorators, &mut self.decorator_stack);
+            let return_type_annotation = if self.match_exact(TokenKind::Arrow).is_some() {
+                Some(self.type_annotation()?)
+            } else {
+                None
+            };
 
-                Ok(Statement::DefineFunction {
-                    function_name_span,
-                    function_name: fn_name.lexeme.clone(),
-                    type_parameters,
-                    parameters,
-                    body,
-                    return_type_annotation,
-                    decorators,
-                })
+            let body = if self.match_exact(TokenKind::Equal).is_none() {
+                None
             } else {
-                Err(ParseError {
-                    kind: ParseErrorKind::ExpectedIdentifierAfterFn,
+                self.skip_empty_lines();
+                Some(self.expression()?)
+            };
+
+            if decorator::contains_aliases(&self.decorator_stack) {
+                return Err(ParseError {
+                    kind: ParseErrorKind::AliasUsedOnFunction,
                     span: self.peek().span,
-                })
+                });
             }
-        } else if self.match_exact(TokenKind::Dimension).is_some() {
-            if let Some(identifier) = self.match_exact(TokenKind::Identifier) {
-                if identifier.lexeme.starts_with("__") {
-                    return Err(ParseError::new(
-                        ParseErrorKind::DoubleUnderscoreTypeNamesReserved,
-                        identifier.span,
-                    ));
-                }
 
-                if self.match_exact(TokenKind::Equal).is_some() {
-                    self.skip_empty_lines();
-                    let mut dexprs = vec![self.dimension_expression()?];
+            let mut decorators = vec![];
+            std::mem::swap(&mut decorators, &mut self.decorator_stack);
+
+            Ok(Statement::DefineFunction {
+                function_name_span,
+                function_name: fn_name.lexeme.clone(),
+                type_parameters,
+                parameters,
+                body,
+                return_type_annotation,
+                decorators,
+            })
+        } else {
+            Err(ParseError {
+                kind: ParseErrorKind::ExpectedIdentifierAfterFn,
+                span: self.peek().span,
+            })
+        }
+    }
 
-                    while self.match_exact(TokenKind::Equal).is_some() {
-                        self.skip_empty_lines();
-                        dexprs.push(self.dimension_expression()?);
-                    }
+    fn parse_dimension_declaration(&mut self) -> Result<Statement> {
+        if let Some(identifier) = self.match_exact(TokenKind::Identifier) {
+            if identifier.lexeme.starts_with("__") {
+                return Err(ParseError::new(
+                    ParseErrorKind::DoubleUnderscoreTypeNamesReserved,
+                    identifier.span,
+                ));
+            }
 
-                    Ok(Statement::DefineDimension(
-                        identifier.span,
-                        identifier.lexeme.clone(),
-                        dexprs,
-                    ))
-                } else {
-                    Ok(Statement::DefineDimension(
-                        identifier.span,
-                        identifier.lexeme.clone(),
-                        vec![],
-                    ))
+            if self.match_exact(TokenKind::Equal).is_some() {
+                self.skip_empty_lines();
+                let mut dexprs = vec![self.dimension_expression()?];
+
+                while self.match_exact(TokenKind::Equal).is_some() {
+                    self.skip_empty_lines();
+                    dexprs.push(self.dimension_expression()?);
                 }
+
+                Ok(Statement::DefineDimension(
+                    identifier.span,
+                    identifier.lexeme.clone(),
+                    dexprs,
+                ))
             } else {
-                Err(ParseError {
-                    kind: ParseErrorKind::ExpectedIdentifierAfterDimension,
-                    span: self.peek().span,
-                })
+                Ok(Statement::DefineDimension(
+                    identifier.span,
+                    identifier.lexeme.clone(),
+                    vec![],
+                ))
             }
-        } else if self.match_exact(TokenKind::At).is_some() {
-            if let Some(decorator) = self.match_exact(TokenKind::Identifier) {
-                let decorator = match decorator.lexeme.as_str() {
-                    "metric_prefixes" => Decorator::MetricPrefixes,
-                    "binary_prefixes" => Decorator::BinaryPrefixes,
-                    "aliases" => {
-                        if self.match_exact(TokenKind::LeftParen).is_some() {
-                            let aliases = self.list_of_aliases()?;
-                            Decorator::Aliases(aliases)
-                        } else {
-                            return Err(ParseError {
-                                kind: ParseErrorKind::ExpectedLeftParenAfterDecorator,
-                                span: self.peek().span,
-                            });
-                        }
+        } else {
+            Err(ParseError {
+                kind: ParseErrorKind::ExpectedIdentifierAfterDimension,
+                span: self.peek().span,
+            })
+        }
+    }
+
+    fn parse_decorators(&mut self) -> Result<Statement> {
+        if let Some(decorator) = self.match_exact(TokenKind::Identifier) {
+            let decorator = match decorator.lexeme.as_str() {
+                "metric_prefixes" => Decorator::MetricPrefixes,
+                "binary_prefixes" => Decorator::BinaryPrefixes,
+                "aliases" => {
+                    if self.match_exact(TokenKind::LeftParen).is_some() {
+                        let aliases = self.list_of_aliases()?;
+                        Decorator::Aliases(aliases)
+                    } else {
+                        return Err(ParseError {
+                            kind: ParseErrorKind::ExpectedLeftParenAfterDecorator,
+                            span: self.peek().span,
+                        });
                     }
-                    "url" | "name" | "description" => {
-                        if self.match_exact(TokenKind::LeftParen).is_some() {
-                            if let Some(token) = self.match_exact(TokenKind::StringFixed) {
-                                if self.match_exact(TokenKind::RightParen).is_none() {
-                                    return Err(ParseError::new(
-                                        ParseErrorKind::MissingClosingParen,
-                                        self.peek().span,
-                                    ));
-                                }
+                }
+                "url" | "name" | "description" => {
+                    if self.match_exact(TokenKind::LeftParen).is_some() {
+                        if let Some(token) = self.match_exact(TokenKind::StringFixed) {
+                            if self.match_exact(TokenKind::RightParen).is_none() {
+                                return Err(ParseError::new(
+                                    ParseErrorKind::MissingClosingParen,
+                                    self.peek().span,
+                                ));
+                            }
 
-                                let content = strip_and_escape(&token.lexeme);
+                            let content = strip_and_escape(&token.lexeme);
 
-                                match decorator.lexeme.as_str() {
-                                    "url" => Decorator::Url(content),
-                                    "name" => Decorator::Name(content),
-                                    "description" => Decorator::Description(content),
-                                    _ => unreachable!(),
-                                }
-                            } else {
-                                return Err(ParseError {
-                                    kind: ParseErrorKind::ExpectedString,
-                                    span: self.peek().span,
-                                });
+                            match decorator.lexeme.as_str() {
+                                "url" => Decorator::Url(content),
+                                "name" => Decorator::Name(content),
+                                "description" => Decorator::Description(content),
+                                _ => unreachable!(),
                             }
                         } else {
                             return Err(ParseError {
-                                kind: ParseErrorKind::ExpectedLeftParenAfterDecorator,
+                                kind: ParseErrorKind::ExpectedString,
                                 span: self.peek().span,
                             });
                         }
-                    }
-                    _ => {
+                    } else {
                         return Err(ParseError {
-                            kind: ParseErrorKind::UnknownDecorator,
-                            span: decorator.span,
+                            kind: ParseErrorKind::ExpectedLeftParenAfterDecorator,
+                            span: self.peek().span,
                         });
                     }
-                };
+                }
+                _ => {
+                    return Err(ParseError {
+                        kind: ParseErrorKind::UnknownDecorator,
+                        span: decorator.span,
+                    });
+                }
+            };
+
+            self.decorator_stack.push(decorator); // TODO: make sure that there are no duplicate decorators
+
+            // A decorator is not yet a full statement. Continue parsing:
+            self.skip_empty_lines();
+            self.statement()
+        } else {
+            Err(ParseError {
+                kind: ParseErrorKind::ExpectedDecoratorName,
+                span: self.peek().span,
+            })
+        }
+    }
 
-                self.decorator_stack.push(decorator); // TODO: make sure that there are no duplicate decorators
+    fn parse_unit_declaration(&mut self) -> Result<Statement> {
+        if let Some(identifier) = self.match_exact(TokenKind::Identifier) {
+            let identifier_span = self.last().unwrap().span;
+            let (type_annotation_span, dexpr) = if self.match_exact(TokenKind::Colon).is_some() {
+                let type_annotation = self.dimension_expression()?;
+                (Some(self.last().unwrap().span), Some(type_annotation))
+            } else {
+                (None, None)
+            };
+
+            let unit_name = identifier.lexeme.clone();
+
+            let mut decorators = vec![];
+            std::mem::swap(&mut decorators, &mut self.decorator_stack);
 
-                // A decorator is not yet a full statement. Continue parsing:
+            if self.match_exact(TokenKind::Equal).is_some() {
                 self.skip_empty_lines();
-                self.statement()
+                let expr = self.expression()?;
+                Ok(Statement::DefineDerivedUnit {
+                    identifier_span,
+                    identifier: unit_name,
+                    expr,
+                    type_annotation_span,
+                    type_annotation: dexpr.map(TypeAnnotation::TypeExpression),
+                    decorators,
+                })
+            } else if dexpr.is_some() {
+                Ok(Statement::DefineBaseUnit(
+                    identifier_span,
+                    unit_name,
+                    dexpr,
+                    decorators,
+                ))
+            } else if self.is_end_of_statement() {
+                Ok(Statement::DefineBaseUnit(
+                    identifier_span,
+                    unit_name,
+                    None,
+                    decorators,
+                ))
             } else {
                 Err(ParseError {
-                    kind: ParseErrorKind::ExpectedDecoratorName,
+                    kind: ParseErrorKind::ExpectedColonOrEqualAfterUnitIdentifier,
                     span: self.peek().span,
                 })
             }
-        } else if self.match_exact(TokenKind::Unit).is_some() {
-            if let Some(identifier) = self.match_exact(TokenKind::Identifier) {
-                let identifier_span = self.last().unwrap().span;
-                let (type_annotation_span, dexpr) = if self.match_exact(TokenKind::Colon).is_some()
-                {
-                    let type_annotation = self.dimension_expression()?;
-                    (Some(self.last().unwrap().span), Some(type_annotation))
-                } else {
-                    (None, None)
-                };
+        } else {
+            Err(ParseError {
+                kind: ParseErrorKind::ExpectedIdentifierAfterUnit,
+                span: self.peek().span,
+            })
+        }
+    }
 
-                let unit_name = identifier.lexeme.clone();
+    fn parse_use(&mut self) -> Result<Statement> {
+        let mut span = self.peek().span;
 
-                let mut decorators = vec![];
-                std::mem::swap(&mut decorators, &mut self.decorator_stack);
+        if let Some(identifier) = self.match_exact(TokenKind::Identifier) {
+            let mut module_path = vec![identifier.lexeme.clone()];
 
-                if self.match_exact(TokenKind::Equal).is_some() {
-                    self.skip_empty_lines();
-                    let expr = self.expression()?;
-                    Ok(Statement::DefineDerivedUnit {
-                        identifier_span,
-                        identifier: unit_name,
-                        expr,
-                        type_annotation_span,
-                        type_annotation: dexpr.map(TypeAnnotation::TypeExpression),
-                        decorators,
-                    })
-                } else if dexpr.is_some() {
-                    Ok(Statement::DefineBaseUnit(
-                        identifier_span,
-                        unit_name,
-                        dexpr,
-                        decorators,
-                    ))
-                } else if self.is_end_of_statement() {
-                    Ok(Statement::DefineBaseUnit(
-                        identifier_span,
-                        unit_name,
-                        None,
-                        decorators,
-                    ))
+            while self.match_exact(TokenKind::DoubleColon).is_some() {
+                if let Some(identifier) = self.match_exact(TokenKind::Identifier) {
+                    module_path.push(identifier.lexeme.clone());
                 } else {
-                    Err(ParseError {
-                        kind: ParseErrorKind::ExpectedColonOrEqualAfterUnitIdentifier,
+                    return Err(ParseError {
+                        kind: ParseErrorKind::ExpectedModuleNameAfterDoubleColon,
                         span: self.peek().span,
-                    })
+                    });
                 }
-            } else {
-                Err(ParseError {
-                    kind: ParseErrorKind::ExpectedIdentifierAfterUnit,
-                    span: self.peek().span,
-                })
             }
-        } else if self.match_exact(TokenKind::Use).is_some() {
-            let mut span = self.peek().span;
+            span = span.extend(&self.last().unwrap().span);
 
-            if let Some(identifier) = self.match_exact(TokenKind::Identifier) {
-                let mut module_path = vec![identifier.lexeme.clone()];
+            Ok(Statement::ModuleImport(span, ModulePath(module_path)))
+        } else {
+            Err(ParseError {
+                kind: ParseErrorKind::ExpectedModulePathAfterUse,
+                span: self.peek().span,
+            })
+        }
+    }
 
-                while self.match_exact(TokenKind::DoubleColon).is_some() {
-                    if let Some(identifier) = self.match_exact(TokenKind::Identifier) {
-                        module_path.push(identifier.lexeme.clone());
-                    } else {
-                        return Err(ParseError {
-                            kind: ParseErrorKind::ExpectedModuleNameAfterDoubleColon,
-                            span: self.peek().span,
-                        });
-                    }
-                }
-                span = span.extend(&self.last().unwrap().span);
+    fn parse_struct(&mut self) -> Result<Statement> {
+        let name = self.identifier()?;
+        let name_span = self.last().unwrap().span;
 
-                Ok(Statement::ModuleImport(span, ModulePath(module_path)))
-            } else {
-                Err(ParseError {
-                    kind: ParseErrorKind::ExpectedModulePathAfterUse,
-                    span: self.peek().span,
-                })
-            }
-        } else if self.match_exact(TokenKind::Struct).is_some() {
-            let name = self.identifier()?;
-            let name_span = self.last().unwrap().span;
+        if self.match_exact(TokenKind::LeftCurly).is_none() {
+            return Err(ParseError {
+                kind: ParseErrorKind::ExpectedLeftCurlyAfterStructName,
+                span: self.peek().span,
+            });
+        }
+
+        self.skip_empty_lines();
 
-            if self.match_exact(TokenKind::LeftCurly).is_none() {
+        let mut fields = vec![];
+        while self.match_exact(TokenKind::RightCurly).is_none() {
+            self.skip_empty_lines();
+
+            let Some(field_name) = self.match_exact(TokenKind::Identifier) else {
                 return Err(ParseError {
-                    kind: ParseErrorKind::ExpectedLeftCurlyAfterStructName,
+                    kind: ParseErrorKind::ExpectedFieldNameInStruct,
                     span: self.peek().span,
                 });
-            }
+            };
 
             self.skip_empty_lines();
 
-            let mut fields = vec![];
-            while self.match_exact(TokenKind::RightCurly).is_none() {
-                self.skip_empty_lines();
-
-                let Some(field_name) = self.match_exact(TokenKind::Identifier) else {
-                    return Err(ParseError {
-                        kind: ParseErrorKind::ExpectedFieldNameInStruct,
-                        span: self.peek().span,
-                    });
-                };
-
-                self.skip_empty_lines();
+            if self.match_exact(TokenKind::Colon).is_none() {
+                return Err(ParseError {
+                    kind: ParseErrorKind::ExpectedColonAfterFieldName,
+                    span: self.peek().span,
+                });
+            }
+            self.skip_empty_lines();
 
-                if self.match_exact(TokenKind::Colon).is_none() {
-                    return Err(ParseError {
-                        kind: ParseErrorKind::ExpectedColonAfterFieldName,
-                        span: self.peek().span,
-                    });
-                }
-                self.skip_empty_lines();
+            let attr_type = self.type_annotation()?;
 
-                let attr_type = self.type_annotation()?;
+            self.skip_empty_lines();
 
-                self.skip_empty_lines();
+            let has_comma = self.match_exact(TokenKind::Comma).is_some();
 
-                let has_comma = self.match_exact(TokenKind::Comma).is_some();
+            self.skip_empty_lines();
 
-                self.skip_empty_lines();
+            if !has_comma && self.peek().kind != TokenKind::RightCurly {
+                return Err(ParseError {
+                    kind: ParseErrorKind::ExpectedCommaOrRightCurlyInStructFieldList,
+                    span: self.peek().span,
+                });
+            }
 
-                if !has_comma && self.peek().kind != TokenKind::RightCurly {
-                    return Err(ParseError {
-                        kind: ParseErrorKind::ExpectedCommaOrRightCurlyInStructFieldList,
-                        span: self.peek().span,
-                    });
-                }
+            fields.push((field_name.span, field_name.lexeme.to_owned(), attr_type));
+        }
 
-                fields.push((field_name.span, field_name.lexeme.to_owned(), attr_type));
-            }
+        Ok(Statement::DefineStruct {
+            struct_name_span: name_span,
+            struct_name: name,
+            fields,
+        })
+    }
 
-            Ok(Statement::DefineStruct {
-                struct_name_span: name_span,
-                struct_name: name,
-                fields,
-            })
-        } else if self.match_any(PROCEDURES).is_some() {
-            let span = self.last().unwrap().span;
-            let procedure_kind = match self.last().unwrap().kind {
-                TokenKind::ProcedurePrint => ProcedureKind::Print,
-                TokenKind::ProcedureAssert => ProcedureKind::Assert,
-                TokenKind::ProcedureAssertEq => ProcedureKind::AssertEq,
-                TokenKind::ProcedureType => ProcedureKind::Type,
-                _ => unreachable!(),
-            };
+    fn parse_procedure(&mut self) -> Result<Statement> {
+        let span = self.last().unwrap().span;
+        let procedure_kind = match self.last().unwrap().kind {
+            TokenKind::ProcedurePrint => ProcedureKind::Print,
+            TokenKind::ProcedureAssert => ProcedureKind::Assert,
+            TokenKind::ProcedureAssertEq => ProcedureKind::AssertEq,
+            TokenKind::ProcedureType => ProcedureKind::Type,
+            _ => unreachable!(),
+        };
 
-            if self.match_exact(TokenKind::LeftParen).is_some() {
-                Ok(Statement::ProcedureCall(
-                    span,
-                    procedure_kind,
-                    self.arguments()?,
-                ))
-            } else {
-                Err(ParseError {
-                    kind: ParseErrorKind::ExpectedLeftParenAfterProcedureName,
-                    span: self.peek().span,
-                })
-            }
+        if self.match_exact(TokenKind::LeftParen).is_some() {
+            Ok(Statement::ProcedureCall(
+                span,
+                procedure_kind,
+                self.arguments()?,
+            ))
         } else {
-            Ok(Statement::Expression(self.expression()?))
+            Err(ParseError {
+                kind: ParseErrorKind::ExpectedLeftParenAfterProcedureName,
+                span: self.peek().span,
+            })
         }
     }