Skip to content

Commit 24f85e8

Browse files
Update interpreter for new annotation form.
1 parent 113faf4 commit 24f85e8

3 files changed

Lines changed: 118 additions & 59 deletions

File tree

src/builtins.c

Lines changed: 9 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6572,45 +6572,25 @@ static Value builtin_signature(Interpreter* interp, Value* args, int argc, Expr*
65726572
if (entry && entry->initialized) {
65736573
if (entry->value.type == VAL_FUNC && entry->value.as.func != NULL) {
65746574
struct Func* f = entry->value.as.func;
6575-
// Build signature in the canonical form: "FUNC R: name(T1: arg1, ... )"
6575+
// Build signature in the canonical form: "R name(T1 arg1, ...)"
65766576
size_t cap = 512;
65776577
char* buf = malloc(cap);
65786578
if (!buf) RUNTIME_ERROR(interp, "Out of memory", line, col);
65796579
buf[0] = '\0';
6580-
const char* rname = "ANY";
6581-
switch (f->return_type) {
6582-
case TYPE_BOOL: rname = "BOOL"; break;
6583-
case TYPE_INT: rname = "INT"; break;
6584-
case TYPE_FLT: rname = "FLT"; break;
6585-
case TYPE_STR: rname = "STR"; break;
6586-
case TYPE_TNS: rname = "TNS"; break;
6587-
case TYPE_MAP: rname = "MAP"; break;
6588-
case TYPE_FUNC: rname = "FUNC"; break;
6589-
case TYPE_THR: rname = "THR"; break;
6590-
default: rname = "ANY"; break;
6591-
}
6580+
const char* rname = decl_type_name(f->return_type);
6581+
if (strcmp(rname, "UNKNOWN") == 0) rname = "ANY";
65926582
strcat(buf, rname);
6593-
strcat(buf, ": ");
6583+
strcat(buf, " ");
65946584
strcat(buf, f->name ? f->name : name);
65956585
strcat(buf, "(");
65966586
for (size_t i = 0; i < f->params.count; i++) {
65976587
Param p = f->params.items[i];
6598-
const char* tname = "UNKNOWN";
6599-
switch (p.type) {
6600-
case TYPE_BOOL: tname = "BOOL"; break;
6601-
case TYPE_INT: tname = "INT"; break;
6602-
case TYPE_FLT: tname = "FLT"; break;
6603-
case TYPE_STR: tname = "STR"; break;
6604-
case TYPE_TNS: tname = "TNS"; break;
6605-
case TYPE_MAP: tname = "MAP"; break;
6606-
case TYPE_FUNC: tname = "FUNC"; break;
6607-
case TYPE_THR: tname = "THR"; break;
6608-
default: tname = "ANY"; break;
6609-
}
6588+
const char* tname = decl_type_name(p.type);
6589+
if (strcmp(tname, "UNKNOWN") == 0) tname = "ANY";
66106590
if (i > 0) strcat(buf, ", ");
66116591
if (p.coerced) strcat(buf, "~");
66126592
strcat(buf, tname);
6613-
strcat(buf, ": ");
6593+
strcat(buf, " ");
66146594
strcat(buf, p.name ? p.name : "");
66156595
if (p.default_value != NULL) {
66166596
Value dv = eval_expr(interp, p.default_value, f->closure);
@@ -6649,7 +6629,7 @@ static Value builtin_signature(Interpreter* interp, Value* args, int argc, Expr*
66496629
}
66506630
}
66516631

6652-
// Non-function: return "TYPE: name" using declared type if available
6632+
// Non-function: return "TYPE name" using declared type if available
66536633
if (!entry) {
66546634
RUNTIME_ERROR(interp, "SIGNATURE: identifier not found or uninitialized", line, col);
66556635
}
@@ -6668,7 +6648,7 @@ static Value builtin_signature(Interpreter* interp, Value* args, int argc, Expr*
66686648
size_t len = strlen(tname) + 2 + strlen(name) + 1;
66696649
char* res = malloc(len + 1);
66706650
if (!res) RUNTIME_ERROR(interp, "Out of memory", line, col);
6671-
snprintf(res, len + 1, "%s: %s", tname, name);
6651+
snprintf(res, len + 1, "%s %s", tname, name);
66726652
Value out = value_str(res);
66736653
free(res);
66746654
return out;

src/parser.c

Lines changed: 108 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -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

3839
static 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+
91170
static 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+
211301
static 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) {
245332
static 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) {
752836
static 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

781861
static 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;

src/parser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ typedef struct {
1010
Token current_token;
1111
Token previous_token;
1212
Token next_token;
13+
Token lookahead2_token;
1314
bool panic_mode;
1415
bool had_error;
1516
char* error_msg;

0 commit comments

Comments
 (0)