@@ -33,12 +33,14 @@ void parser_init(Parser* parser, Lexer* lexer) {
3333 parser -> error_col = 0 ;
3434 parser -> current_token = lexer_next_token (parser -> lexer );
3535 parser -> next_token = lexer_next_token (parser -> lexer );
36+ parser -> lookahead2_token = lexer_next_token (parser -> lexer );
3637}
3738
3839static void advance (Parser * parser ) {
3940 parser -> previous_token = parser -> current_token ;
4041 parser -> current_token = parser -> next_token ;
41- parser -> next_token = lexer_next_token (parser -> lexer );
42+ parser -> next_token = parser -> lookahead2_token ;
43+ parser -> lookahead2_token = lexer_next_token (parser -> lexer );
4244
4345 /* If the lexer produced an error token, report it and advance until
4446 we reach a non-error token. Use a loop instead of recursion so the
@@ -50,7 +52,8 @@ static void advance(Parser* parser) {
5052
5153 parser -> previous_token = parser -> current_token ;
5254 parser -> current_token = parser -> next_token ;
53- parser -> next_token = lexer_next_token (parser -> lexer );
55+ parser -> next_token = parser -> lookahead2_token ;
56+ parser -> lookahead2_token = lexer_next_token (parser -> lexer );
5457 }
5558}
5659
@@ -88,6 +91,82 @@ static DeclType parse_type_name(const char* name) {
8891 return TYPE_UNKNOWN ;
8992}
9093
94+ static const char * k_type_name_gap_error = "Type annotations require one or more spaces between type and name" ;
95+
96+ static size_t token_source_width (const Token * token ) {
97+ if (!token ) return 0 ;
98+ if (token -> literal ) return strlen (token -> literal );
99+
100+ switch (token -> type ) {
101+ case TOKEN_FUNC : return 4 ;
102+ case TOKEN_THR : return 3 ;
103+ default : return 0 ;
104+ }
105+ }
106+
107+ static bool require_space_only_gap (Parser * parser , const Token * left , const Token * right , const char * message ) {
108+ char * line_text ;
109+ size_t line_len ;
110+ size_t left_width ;
111+ int gap_start_col ;
112+ int gap_end_col ;
113+
114+ if (!left || !right || right -> type != TOKEN_IDENT ) {
115+ report_error (parser , message );
116+ return false;
117+ }
118+ if (left -> line != right -> line ) {
119+ report_error (parser , message );
120+ return false;
121+ }
122+
123+ left_width = token_source_width (left );
124+ if (left_width == 0 ) {
125+ report_error (parser , message );
126+ return false;
127+ }
128+
129+ gap_start_col = left -> column + (int )left_width ;
130+ gap_end_col = right -> column - 1 ;
131+ if (gap_end_col < gap_start_col ) {
132+ report_error (parser , message );
133+ return false;
134+ }
135+
136+ line_text = lexer_get_line (parser -> lexer , left -> line );
137+ if (!line_text ) {
138+ report_error (parser , message );
139+ return false;
140+ }
141+
142+ line_len = strlen (line_text );
143+ if ((size_t )gap_end_col > line_len ) {
144+ free (line_text );
145+ report_error (parser , message );
146+ return false;
147+ }
148+
149+ for (int col = gap_start_col ; col <= gap_end_col ; col ++ ) {
150+ if (line_text [col - 1 ] != ' ' ) {
151+ free (line_text );
152+ report_error (parser , message );
153+ return false;
154+ }
155+ }
156+
157+ free (line_text );
158+ return true;
159+ }
160+
161+ static bool advance_to_annotated_name (Parser * parser , const char * message ) {
162+ if (!require_space_only_gap (parser , & parser -> current_token , & parser -> next_token , message )) {
163+ return false;
164+ }
165+
166+ advance (parser );
167+ return true;
168+ }
169+
91170static int base_from_literal_prefix (const char * s , size_t * prefix_len ) {
92171 if (!s || s [0 ] != '0' ) return -1 ;
93172 char p = s [1 ];
@@ -208,6 +287,17 @@ static bool is_type_token(PTokenType type) {
208287 return type == TOKEN_IDENT || type == TOKEN_FUNC || type == TOKEN_THR ;
209288}
210289
290+ static bool starts_named_type_annotation (Parser * parser ) {
291+ return is_type_token (parser -> current_token .type ) &&
292+ (parser -> next_token .type == TOKEN_IDENT || parser -> next_token .type == TOKEN_COLON );
293+ }
294+
295+ static bool looks_like_func_definition (Parser * parser ) {
296+ return parser -> current_token .type == TOKEN_FUNC &&
297+ is_type_token (parser -> next_token .type ) &&
298+ (parser -> lookahead2_token .type == TOKEN_IDENT || parser -> lookahead2_token .type == TOKEN_COLON );
299+ }
300+
211301static bool parse_param_list (Parser * parser , ParamList * params ) {
212302 if (parser -> current_token .type == TOKEN_RPAREN ) return true;
213303 do {
@@ -221,10 +311,7 @@ static bool parse_param_list(Parser* parser, ParamList* params) {
221311 return false;
222312 }
223313 DeclType ptype = parse_type_name (parser -> current_token .literal );
224- advance (parser );
225- consume (parser , TOKEN_COLON , "Expected ':' after parameter type" );
226- if (parser -> current_token .type != TOKEN_IDENT ) {
227- report_error (parser , "Expected parameter name" );
314+ if (!advance_to_annotated_name (parser , k_type_name_gap_error )) {
228315 return false;
229316 }
230317 Param param ;
@@ -245,10 +332,7 @@ static bool parse_param_list(Parser* parser, ParamList* params) {
245332static Expr * parse_typed_ident_expr (Parser * parser ) {
246333 Token type_tok = parser -> current_token ;
247334 DeclType dtype = parse_type_name (type_tok .literal );
248- advance (parser );
249- consume (parser , TOKEN_COLON , "Expected ':' after type" );
250- if (parser -> current_token .type != TOKEN_IDENT ) {
251- report_error (parser , "Expected identifier name" );
335+ if (!advance_to_annotated_name (parser , k_type_name_gap_error )) {
252336 return NULL ;
253337 }
254338 char * name = parser -> current_token .literal ;
@@ -501,7 +585,7 @@ static Expr* parse_call(Parser* parser) {
501585 call -> as .call .args .count == 0 &&
502586 call -> as .call .kw_count == 0 &&
503587 is_type_token (parser -> current_token .type ) &&
504- parser -> next_token .type == TOKEN_COLON ;
588+ ( parser -> next_token .type == TOKEN_IDENT || parser -> next_token . type == TOKEN_COLON ) ;
505589
506590 bool is_extend_specifier =
507591 call -> as .call .callee -> type == EXPR_IDENT &&
@@ -752,17 +836,13 @@ static Stmt* parse_try(Parser* parser) {
752836static Stmt * parse_func (Parser * parser ) {
753837 Token tok = parser -> current_token ;
754838 consume (parser , TOKEN_FUNC , "Expected 'FUNC'" );
755- /* FUNC R: name( params ) { body } */
839+ /* FUNC R name( params ) { body } */
756840 if (!is_type_token (parser -> current_token .type )) {
757841 report_error (parser , "Expected return type after FUNC" );
758842 return NULL ;
759843 }
760844 DeclType ret = parse_type_name (parser -> current_token .literal );
761- advance (parser );
762- consume (parser , TOKEN_COLON , "Expected ':' after return type" );
763-
764- if (parser -> current_token .type != TOKEN_IDENT ) {
765- report_error (parser , "Expected function name" );
845+ if (!advance_to_annotated_name (parser , k_type_name_gap_error )) {
766846 return NULL ;
767847 }
768848 char * name = parser -> current_token .literal ;
@@ -780,18 +860,19 @@ static Stmt* parse_func(Parser* parser) {
780860
781861static Stmt * parse_statement (Parser * parser ) {
782862 skip_newlines (parser );
783- // Handle typed declarations where the type token may be a keyword like THR
784- if ((parser -> current_token .type == TOKEN_IDENT || parser -> current_token .type == TOKEN_THR || parser -> current_token .type == TOKEN_FUNC ) && parser -> next_token .type == TOKEN_COLON ) {
863+ if (looks_like_func_definition (parser )) {
864+ return parse_func (parser );
865+ }
866+
867+ // Handle typed declarations where the type token may be a keyword like THR.
868+ if (starts_named_type_annotation (parser )) {
785869 Token type_tok = parser -> current_token ;
786- advance (parser );
787- consume (parser , TOKEN_COLON , "Expected ':' after type" );
788- if (parser -> current_token .type != TOKEN_IDENT ) {
789- report_error (parser , "Expected identifier name" );
870+ DeclType dtype = parse_type_name (type_tok .literal );
871+ if (!advance_to_annotated_name (parser , k_type_name_gap_error )) {
790872 return NULL ;
791873 }
792874 char * name = parser -> current_token .literal ;
793875 advance (parser );
794- DeclType dtype = parse_type_name (type_tok .literal );
795876 // Support typed declaration with indexed-assignment target, e.g. `TNS: t[1-10] = ...`
796877 if (parser -> current_token .type == TOKEN_LBRACKET || parser -> current_token .type == TOKEN_LANGLE ) {
797878 // construct base identifier expr and parse trailing indexers
@@ -992,17 +1073,14 @@ static Stmt* parse_statement(Parser* parser) {
9921073 break ;
9931074 }
9941075
995- if ((parser -> current_token . type == TOKEN_IDENT || parser -> current_token . type == TOKEN_THR || parser -> current_token . type == TOKEN_FUNC ) && parser -> next_token . type == TOKEN_COLON ) {
1076+ if (starts_named_type_annotation (parser ) ) {
9961077 Token type_tok = parser -> current_token ;
997- advance (parser );
998- consume (parser , TOKEN_COLON , "Expected ':' after type" );
999- if (parser -> current_token .type != TOKEN_IDENT ) {
1000- report_error (parser , "Expected identifier name" );
1078+ DeclType dtype = parse_type_name (type_tok .literal );
1079+ if (!advance_to_annotated_name (parser , k_type_name_gap_error )) {
10011080 return NULL ;
10021081 }
10031082 char * name = parser -> current_token .literal ;
10041083 advance (parser );
1005- DeclType dtype = parse_type_name (type_tok .literal );
10061084 if (match (parser , TOKEN_EQUALS )) {
10071085 Expr * expr = parse_expression (parser );
10081086 if (!expr ) return NULL ;
0 commit comments