@@ -39,6 +39,7 @@ pub enum ParsingError {
3939 InvalidForma ( usize ) ,
4040 InvalidGenus ( usize ) ,
4141 InvalidSignature ( usize ) ,
42+ InvalidParameters ( usize ) ,
4243 InvalidDeclaration ( usize ) ,
4344 InvalidSection ( usize ) ,
4445 InvalidInvocation ( usize ) ,
@@ -76,6 +77,7 @@ impl ParsingError {
7677 ParsingError :: InvalidGenus ( offset) => * offset,
7778 ParsingError :: InvalidSignature ( offset) => * offset,
7879 ParsingError :: InvalidDeclaration ( offset) => * offset,
80+ ParsingError :: InvalidParameters ( offset) => * offset,
7981 ParsingError :: InvalidSection ( offset) => * offset,
8082 ParsingError :: InvalidInvocation ( offset) => * offset,
8183 ParsingError :: InvalidFunction ( offset) => * offset,
@@ -281,15 +283,12 @@ impl<'i> Parser<'i> {
281283 . push ( error) ;
282284 }
283285 }
284- } else if self
285- . source
286- . contains ( ':' )
287- {
286+ } else if potential_procedure_declaration ( self . source ) {
288287 // It might be that we've encountered a malformed procedure
289288 // declaration, so we try parsing it anyway to get a more
290289 // specific error message.
291290 match self . take_block_lines (
292- |_| true , // Accept the line regardless
291+ potential_procedure_declaration ,
293292 |line| is_section ( line) || potential_procedure_declaration ( line) ,
294293 |inner| inner. read_procedure ( ) ,
295294 ) {
@@ -856,6 +855,25 @@ impl<'i> Parser<'i> {
856855
857856 ( name, parameters)
858857 } else {
858+ // Check if there are multiple words (procedure name + anything
859+ // else) which would indicates parameters without parentheses
860+ let words: Vec < & str > = text
861+ . trim ( )
862+ . split_whitespace ( )
863+ . collect ( ) ;
864+ if words. len ( ) > 1 {
865+ // Calculate position of first mistaken parameter-ish thing
866+ let first_space_pos = text
867+ . find ( ' ' )
868+ . unwrap_or ( 0 ) ;
869+ let first_param_pos = text[ first_space_pos..]
870+ . trim_start ( )
871+ . as_ptr ( ) as isize
872+ - text. as_ptr ( ) as isize ;
873+ let error_offset = self . offset + one. start ( ) + first_param_pos as usize ;
874+ return Err ( ParsingError :: InvalidParameters ( error_offset) ) ;
875+ }
876+
859877 let name = validate_identifier ( text) . ok_or ( ParsingError :: InvalidIdentifier (
860878 self . offset ,
861879 text. to_string ( ) ,
@@ -2559,24 +2577,37 @@ fn is_procedure_declaration(content: &str) -> bool {
25592577/// reporting what turns out to be a better error.
25602578fn potential_procedure_declaration ( content : & str ) -> bool {
25612579 match content. split_once ( ':' ) {
2562- Some ( ( before, _after ) ) => {
2580+ Some ( ( before, after ) ) => {
25632581 let before = before. trim_ascii ( ) ;
2564- // Check if it looks like an identifier (possibly with parameters)
2565- // Accept any single token that could be an attempted identifier
2566- if let Some ( ( name, params) ) = before. split_once ( '(' ) {
2567- // Has parameters: check if params end with ')'
2568- !name
2582+
2583+ // Empty before colon -> only a declaration if there's something after
2584+ if before. is_empty ( ) {
2585+ return !after
25692586 . trim_ascii ( )
2570- . is_empty ( )
2571- && params. ends_with ( ')' )
2572- } else {
2573- // No parameters: must be a single token (no spaces) that
2574- // looks identifier-ish This excludes sentences like "Ask
2575- // these questions: ..."
2576- !before. is_empty ( ) &&
2577- !before. contains ( ' ' ) && // Single token only
2578- before. chars ( ) . all ( |c| c. is_ascii_alphanumeric ( ) || c == '_' )
2587+ . is_empty ( ) ;
2588+ }
2589+
2590+ // Has parentheses -> likely trying to be a procedure with parameters
2591+ if before. contains ( '(' ) {
2592+ return true ;
25792593 }
2594+
2595+ // Check if it looks like prose vs an identifier attempt
2596+ // Prose typically: starts with capital, has multiple space-separated words
2597+ // Identifiers: lowercase, possibly with underscores
2598+ let first_char = before
2599+ . chars ( )
2600+ . next ( )
2601+ . unwrap ( ) ;
2602+ let has_spaces = before. contains ( ' ' ) ;
2603+
2604+ // If it starts with uppercase AND has spaces, it's probably prose
2605+ if first_char. is_uppercase ( ) && has_spaces {
2606+ return false ;
2607+ }
2608+
2609+ // Otherwise, could be a procedure declaration attempt
2610+ true
25802611 }
25812612 None => false ,
25822613 }
0 commit comments