Skip to content

Commit ecced12

Browse files
Add named MAP (closed #201)
1 parent 7dc6d6d commit ecced12

33 files changed

Lines changed: 779 additions & 86 deletions

docs/SPECIFICATION.html

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,9 @@
9696

9797
For `INT` and `FLT` types, a declaration MAY name a specific numeric base by writing `TYPE{base} name`, where `base` is an `INT` literal in the range `2` through `64`. A named-base type is a subtype of its parent numeric type: `INT{base}` values are `INT`s and `FLT{base}` values are `FLT`s, but an assignment to a named-base binding requires the value's base to match the declared base. The parent types `INT` and `FLT` (equivalent to `INT{0}` and `FLT{0}`) accept values of any valid numeric base.
9898

99-
The first assignment to a symbol MUST use a typed form such as `TYPE name = expression` or `TYPE{base} name = expression`, with one or more spaces between the type annotation and the name and optional spaces around `=`. Subsequent assignments MAY omit the type annotation, but the symbol's type MUST remain unchanged for the lifetime of that name, including after deletion and re-assignment.
99+
For `MAP` types, a declaration MAY specify a template `MAP` by writing `MAP{template} name`, where `template` is any expression that evaluates to a `MAP`. A named-`MAP` type is a subtype of its parent `MAP` type: `MAP{template}` values are `MAP`s, but an assignment to a named-`MAP` binding requires the assigned value to match the template according to the default key-presence rules of the `MATCH` operator. The parent type `MAP` accepts any `MAP` value.
100+
101+
The first assignment to a symbol MUST use a typed form such as `TYPE name = expression`, `TYPE{base} name = expression`, or `MAP{template} name = expression`, with one or more spaces between the type annotation and the name and optional spaces around `=`. Subsequent assignments MAY omit the type annotation, but the symbol's type MUST remain unchanged for the lifetime of that name, including after deletion and re-assignment.
100102

101103
Assignments to undeclared identifiers without a type annotation MUST raise a runtime error. A binding MUST remain allocated until it is deleted with `DEL("name")`.
102104

@@ -176,6 +178,8 @@
176178
177179
`INT` and `FLT` additionally support named-base variants written `INT{base}` and `FLT{base}`, where `base` is a numeric base in the range `2` through `64` or `0` to denote the parent type. A named-base type and its parent are the same runtime type, but static type checking treats mismatched bases as incompatible. `INT` and `FLT` (base `0`) accept any valid numeric base; `INT{base}` and `FLT{base}` only accept values whose stored base equals the declared base.
178180
181+
`MAP` additionally supports named-template variants written `MAP{template}`, where `template` is any expression that evaluates to a `MAP`. A named-template type and its parent are the same runtime type, but static type checking treats mismatched templates as incompatible. `MAP` accepts any `MAP` value; `MAP{template}` only accepts values whose entries satisfy the template under the default key-presence rules of the `MATCH` operator. Named `MAP` types with different templates are treated as distinct types.
182+
179183
---
180184
181185
### 4.0 Booleans
@@ -438,6 +442,8 @@
438442
439443
`INT` and `FLT` type annotations MAY include a base specifier written immediately after the type name with no intervening whitespace, in the form `INT{base}` or `FLT{base}`. The `{base}` suffix is part of the type annotation and therefore MUST appear before the required space that separates the type from the declared name. For example, `INT{0d2} value` declares a binary integer, while `FLT{0x} value` declares a hexadecimal float. A base of `0` (typically written as the bare type name) denotes the parent type and accepts any valid numeric base.
440444
445+
`MAP` type annotations MAY include a template specifier written immediately after the type name with no intervening whitespace, in the form `MAP{template}`. The `{template}` suffix is part of the type annotation and therefore MUST appear before the required space that separates the type from the declared name. For example, `MAP{<"x" = 0d1>} value` declares a map that requires an `"x"` key with integer value. The `template` MUST evaluate to a `MAP`. Signatures produced by the `SIGNATURE` built-in MUST include the template in the type annotation for named `MAP` bindings.
446+
441447
Reading an undeclared symbol, a declared-but-never-assigned symbol, or a deleted symbol MUST raise a runtime error. Removing a binding MUST preserve its recorded static type, so any later re-assignment to the same name MUST still match the original type.
442448
443449
Re-assignment MUST preserve the declared type for the lifetime of the symbol, including after deletion and re-creation. Symbol existence, lifetime, and mutability MAY be inspected or modified only through the language's dedicated symbol-management facilities.

src/ast.c

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,15 @@ Expr *expr_ident(char *name, int line, int column) {
6161
return expr;
6262
}
6363

64-
Expr *expr_typed_ident(DeclType decl_type, int decl_base, char *name, int line, int column) {
64+
Expr *expr_typed_ident(DeclType decl_type, int decl_base, char *name, Expr *template_expr, int line, int column) {
6565
Expr *expr = ast_alloc(sizeof(Expr));
6666
expr->type = EXPR_TYPED_IDENT;
6767
expr->line = line;
6868
expr->column = column;
6969
expr->as.typed_ident.decl_type = decl_type;
7070
expr->as.typed_ident.decl_base = decl_base;
7171
expr->as.typed_ident.name = name;
72+
expr->as.typed_ident.template_expr = template_expr;
7273
return expr;
7374
}
7475

@@ -146,14 +147,16 @@ Expr *expr_wildcard(int line, int column) {
146147
return expr;
147148
}
148149

149-
Expr *expr_lambda(ParamList params, DeclType return_type, int return_base, Stmt *body, int line, int column) {
150+
Expr *expr_lambda(ParamList params, DeclType return_type, int return_base, Expr *return_template_expr, Stmt *body,
151+
int line, int column) {
150152
Expr *expr = ast_alloc(sizeof(Expr));
151153
expr->type = EXPR_LAMBDA;
152154
expr->line = line;
153155
expr->column = column;
154156
expr->as.lambda.params = params;
155157
expr->as.lambda.return_type = return_type;
156158
expr->as.lambda.return_base = return_base;
159+
expr->as.lambda.return_template_expr = return_template_expr;
157160
expr->as.lambda.body = body;
158161
return expr;
159162
}
@@ -223,8 +226,8 @@ Stmt *stmt_expr(Expr *expr, int line, int column) {
223226
return stmt;
224227
}
225228

226-
Stmt *stmt_assign(bool has_type, DeclType decl_type, int decl_base, char *name, Expr *target, Expr *value, int line,
227-
int column) {
229+
Stmt *stmt_assign(bool has_type, DeclType decl_type, int decl_base, char *name, Expr *target, Expr *value,
230+
Expr *template_expr, int line, int column) {
228231
Stmt *stmt = ast_alloc(sizeof(Stmt));
229232
stmt->type = STMT_ASSIGN;
230233
stmt->line = line;
@@ -235,17 +238,19 @@ Stmt *stmt_assign(bool has_type, DeclType decl_type, int decl_base, char *name,
235238
stmt->as.assign.name = name;
236239
stmt->as.assign.target = target;
237240
stmt->as.assign.value = value;
241+
stmt->as.assign.template_expr = template_expr;
238242
return stmt;
239243
}
240244

241-
Stmt *stmt_decl(DeclType decl_type, int decl_base, char *name, int line, int column) {
245+
Stmt *stmt_decl(DeclType decl_type, int decl_base, char *name, Expr *template_expr, int line, int column) {
242246
Stmt *stmt = ast_alloc(sizeof(Stmt));
243247
stmt->type = STMT_DECL;
244248
stmt->line = line;
245249
stmt->column = column;
246250
stmt->as.decl.decl_type = decl_type;
247251
stmt->as.decl.decl_base = decl_base;
248252
stmt->as.decl.name = name;
253+
stmt->as.decl.template_expr = template_expr;
249254
return stmt;
250255
}
251256

@@ -291,14 +296,16 @@ Stmt *stmt_parfor(char *counter, Expr *target, Stmt *body, int line, int column)
291296
return stmt;
292297
}
293298

294-
Stmt *stmt_func(char *name, DeclType ret, int return_base, Stmt *body, int line, int column) {
299+
Stmt *stmt_func(char *name, DeclType ret, int return_base, Expr *return_template_expr, Stmt *body, int line,
300+
int column) {
295301
Stmt *stmt = ast_alloc(sizeof(Stmt));
296302
stmt->type = STMT_FUNC;
297303
stmt->line = line;
298304
stmt->column = column;
299305
stmt->as.func_stmt.name = name;
300306
stmt->as.func_stmt.return_type = ret;
301307
stmt->as.func_stmt.return_base = return_base;
308+
stmt->as.func_stmt.return_template_expr = return_template_expr;
302309
stmt->as.func_stmt.body = body;
303310
return stmt;
304311
}
@@ -432,6 +439,7 @@ void free_expr(Expr *expr) {
432439
break;
433440
case EXPR_TYPED_IDENT:
434441
free(expr->as.typed_ident.name);
442+
free_expr(expr->as.typed_ident.template_expr);
435443
break;
436444
case EXPR_PTR:
437445
free(expr->as.ptr_name);
@@ -455,8 +463,10 @@ void free_expr(Expr *expr) {
455463
for (size_t i = 0; i < expr->as.lambda.params.count; i++) {
456464
free(expr->as.lambda.params.items[i].name);
457465
free_expr(expr->as.lambda.params.items[i].default_value);
466+
free_expr(expr->as.lambda.params.items[i].template_expr);
458467
}
459468
free(expr->as.lambda.params.items);
469+
free_expr(expr->as.lambda.return_template_expr);
460470
free_stmt(expr->as.lambda.body);
461471
break;
462472
case EXPR_IDENT:
@@ -501,9 +511,11 @@ void free_stmt(Stmt *stmt) {
501511
free_expr(stmt->as.assign.target);
502512
}
503513
free_expr(stmt->as.assign.value);
514+
free_expr(stmt->as.assign.template_expr);
504515
break;
505516
case STMT_DECL:
506517
free(stmt->as.decl.name);
518+
free_expr(stmt->as.decl.template_expr);
507519
break;
508520
case STMT_IF:
509521
free_expr(stmt->as.if_stmt.condition);
@@ -531,8 +543,10 @@ void free_stmt(Stmt *stmt) {
531543
for (size_t i = 0; i < stmt->as.func_stmt.params.count; i++) {
532544
free(stmt->as.func_stmt.params.items[i].name);
533545
free_expr(stmt->as.func_stmt.params.items[i].default_value);
546+
free_expr(stmt->as.func_stmt.params.items[i].template_expr);
534547
}
535548
free(stmt->as.func_stmt.params.items);
549+
free_expr(stmt->as.func_stmt.return_template_expr);
536550
free_stmt(stmt->as.func_stmt.body);
537551
break;
538552
case STMT_RETURN:

src/ast.h

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ typedef struct Param {
2424
char *name;
2525
bool coerced;
2626
Expr *default_value; // optional
27+
Expr *template_expr; // NEW: MAP template expression, NULL if none
2728
} Param;
2829

2930
typedef struct ParamList {
@@ -77,6 +78,7 @@ struct Expr {
7778
DeclType decl_type;
7879
int decl_base; // 0 = parent INT/FLT, 2..64 = named base
7980
char *name;
81+
Expr *template_expr; // NEW: MAP template expression, NULL if none
8082
} typed_ident;
8183
struct {
8284
Expr *callee;
@@ -92,7 +94,8 @@ struct Expr {
9294
struct {
9395
ParamList params;
9496
DeclType return_type;
95-
int return_base; // 0 = parent INT/FLT, 2..64 = named base
97+
int return_base; // 0 = parent INT/FLT, 2..64 = named base
98+
Expr *return_template_expr; // NEW: MAP return template, NULL if none
9699
Stmt *body;
97100
} lambda;
98101
ExprList tns_items;
@@ -157,11 +160,13 @@ struct Stmt {
157160
char *name;
158161
Expr *target;
159162
Expr *value;
163+
Expr *template_expr; // NEW: MAP template expression, NULL if none
160164
} assign;
161165
struct {
162166
DeclType decl_type;
163167
int decl_base; // 0 = parent INT/FLT, 2..64 = named base
164168
char *name;
169+
Expr *template_expr; // NEW: MAP template expression, NULL if none
165170
} decl;
166171
struct {
167172
Expr *condition;
@@ -188,7 +193,8 @@ struct Stmt {
188193
char *name;
189194
ParamList params;
190195
DeclType return_type;
191-
int return_base; // 0 = parent INT/FLT, 2..64 = named base
196+
int return_base; // 0 = parent INT/FLT, 2..64 = named base
197+
Expr *return_template_expr; // NEW: MAP return template, NULL if none
192198
Stmt *body;
193199
} func_stmt;
194200
struct {
@@ -227,7 +233,7 @@ Expr *expr_flt(double value, int base, int base_is_nan, int line, int column);
227233
Expr *expr_str(char *value, int line, int column);
228234
Expr *expr_ptr(char *name, int line, int column);
229235
Expr *expr_ident(char *name, int line, int column);
230-
Expr *expr_typed_ident(DeclType decl_type, int decl_base, char *name, int line, int column);
236+
Expr *expr_typed_ident(DeclType decl_type, int decl_base, char *name, Expr *template_expr, int line, int column);
231237
Expr *expr_call(Expr *callee, int line, int column);
232238
void call_kw_add(Expr *call, char *name, Expr *value);
233239
Expr *expr_tns(int line, int column);
@@ -236,20 +242,22 @@ Expr *expr_map(int line, int column);
236242
Expr *expr_index(Expr *target, int line, int column, bool is_map);
237243
Expr *expr_range(Expr *start, Expr *end, int line, int column);
238244
Expr *expr_wildcard(int line, int column);
239-
Expr *expr_lambda(ParamList params, DeclType return_type, int return_base, Stmt *body, int line, int column);
245+
Expr *expr_lambda(ParamList params, DeclType return_type, int return_base, Expr *return_template_expr, Stmt *body,
246+
int line, int column);
240247
void expr_list_add(ExprList *list, Expr *expr);
241248

242249
Stmt *stmt_block(int line, int column);
243250
Stmt *stmt_async(Stmt *body, int line, int column);
244251
Stmt *stmt_expr(Expr *expr, int line, int column);
245-
Stmt *stmt_assign(bool has_type, DeclType decl_type, int decl_base, char *name, Expr *target, Expr *value, int line,
246-
int column);
247-
Stmt *stmt_decl(DeclType decl_type, int decl_base, char *name, int line, int column);
252+
Stmt *stmt_assign(bool has_type, DeclType decl_type, int decl_base, char *name, Expr *target, Expr *value,
253+
Expr *template_expr, int line, int column);
254+
Stmt *stmt_decl(DeclType decl_type, int decl_base, char *name, Expr *template_expr, int line, int column);
248255
Stmt *stmt_if(Expr *cond, Stmt *then_branch, int line, int column);
249256
Stmt *stmt_while(Expr *cond, Stmt *body, int line, int column);
250257
Stmt *stmt_for(char *counter, Expr *target, Stmt *body, int line, int column);
251258
Stmt *stmt_parfor(char *counter, Expr *target, Stmt *body, int line, int column);
252-
Stmt *stmt_func(char *name, DeclType ret, int return_base, Stmt *body, int line, int column);
259+
Stmt *stmt_func(char *name, DeclType ret, int return_base, Expr *return_template_expr, Stmt *body, int line,
260+
int column);
253261
Stmt *stmt_return(Expr *value, int line, int column);
254262
Stmt *stmt_pop(Expr *expr, int line, int column);
255263
Stmt *stmt_break(Expr *value, int line, int column);

0 commit comments

Comments
 (0)