Skip to content

Commit 3a6cab1

Browse files
Add named INT and FLT (closes #198).
1 parent 254b640 commit 3a6cab1

25 files changed

Lines changed: 676 additions & 367 deletions

docs/SPECIFICATION.html

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

9595
A symbol MAY be declared without a value using `TYPE name`. Such a declaration records the symbol's static type but does not create a readable runtime binding until an assignment occurs. The type and name MUST be separated by one or more space characters, and no other character MAY appear between them.
9696

97-
The first assignment to a symbol MUST use a typed form such as `TYPE name = expression`, with one or more spaces between the type and 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.
97+
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.
98+
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.
98100

99101
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")`.
100102

@@ -172,6 +174,8 @@
172174
173175
Prefix MUST support eight types: `BOOL` (booleans), `STR` (strings), `INT` (integers), `FLT` (floating-point numbers), `TNS` (tensors), `MAP` (maps), `FUNC` (functions), and `THR` (threads). The type of a symbol is determined when it is first declared, and cannot be changed, even after deletion of the original symbol.
174176
177+
`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.
178+
175179
---
176180
177181
### 4.0 Booleans
@@ -432,6 +436,8 @@
432436
433437
A declaration MUST record the symbol's static type without necessarily creating a readable runtime value. A readable binding is created only when a value is first assigned. In all type annotations, the type and name MUST be separated by one or more space characters, and other characters MUST NOT appear between them.
434438
439+
`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.
440+
435441
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.
436442
437443
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: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,13 @@ Expr *expr_ident(char *name, int line, int column) {
6161
return expr;
6262
}
6363

64-
Expr *expr_typed_ident(DeclType decl_type, char *name, int line, int column) {
64+
Expr *expr_typed_ident(DeclType decl_type, int decl_base, char *name, 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;
70+
expr->as.typed_ident.decl_base = decl_base;
7071
expr->as.typed_ident.name = name;
7172
return expr;
7273
}
@@ -145,13 +146,14 @@ Expr *expr_wildcard(int line, int column) {
145146
return expr;
146147
}
147148

148-
Expr *expr_lambda(ParamList params, DeclType return_type, Stmt *body, int line, int column) {
149+
Expr *expr_lambda(ParamList params, DeclType return_type, int return_base, Stmt *body, int line, int column) {
149150
Expr *expr = ast_alloc(sizeof(Expr));
150151
expr->type = EXPR_LAMBDA;
151152
expr->line = line;
152153
expr->column = column;
153154
expr->as.lambda.params = params;
154155
expr->as.lambda.return_type = return_type;
156+
expr->as.lambda.return_base = return_base;
155157
expr->as.lambda.body = body;
156158
return expr;
157159
}
@@ -221,25 +223,28 @@ Stmt *stmt_expr(Expr *expr, int line, int column) {
221223
return stmt;
222224
}
223225

224-
Stmt *stmt_assign(bool has_type, DeclType decl_type, char *name, Expr *target, Expr *value, int line, int column) {
226+
Stmt *stmt_assign(bool has_type, DeclType decl_type, int decl_base, char *name, Expr *target, Expr *value, int line,
227+
int column) {
225228
Stmt *stmt = ast_alloc(sizeof(Stmt));
226229
stmt->type = STMT_ASSIGN;
227230
stmt->line = line;
228231
stmt->column = column;
229232
stmt->as.assign.has_type = has_type;
230233
stmt->as.assign.decl_type = decl_type;
234+
stmt->as.assign.decl_base = decl_base;
231235
stmt->as.assign.name = name;
232236
stmt->as.assign.target = target;
233237
stmt->as.assign.value = value;
234238
return stmt;
235239
}
236240

237-
Stmt *stmt_decl(DeclType decl_type, char *name, int line, int column) {
241+
Stmt *stmt_decl(DeclType decl_type, int decl_base, char *name, int line, int column) {
238242
Stmt *stmt = ast_alloc(sizeof(Stmt));
239243
stmt->type = STMT_DECL;
240244
stmt->line = line;
241245
stmt->column = column;
242246
stmt->as.decl.decl_type = decl_type;
247+
stmt->as.decl.decl_base = decl_base;
243248
stmt->as.decl.name = name;
244249
return stmt;
245250
}
@@ -286,13 +291,14 @@ Stmt *stmt_parfor(char *counter, Expr *target, Stmt *body, int line, int column)
286291
return stmt;
287292
}
288293

289-
Stmt *stmt_func(char *name, DeclType ret, Stmt *body, int line, int column) {
294+
Stmt *stmt_func(char *name, DeclType ret, int return_base, Stmt *body, int line, int column) {
290295
Stmt *stmt = ast_alloc(sizeof(Stmt));
291296
stmt->type = STMT_FUNC;
292297
stmt->line = line;
293298
stmt->column = column;
294299
stmt->as.func_stmt.name = name;
295300
stmt->as.func_stmt.return_type = ret;
301+
stmt->as.func_stmt.return_base = return_base;
296302
stmt->as.func_stmt.body = body;
297303
return stmt;
298304
}

src/ast.h

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ typedef struct Stmt Stmt;
2020

2121
typedef struct Param {
2222
DeclType type;
23+
int num_base; // 0 = parent INT/FLT, 2..64 = named base
2324
char *name;
2425
bool coerced;
2526
Expr *default_value; // optional
@@ -74,12 +75,9 @@ struct Expr {
7475
char *ident;
7576
struct {
7677
DeclType decl_type;
78+
int decl_base; // 0 = parent INT/FLT, 2..64 = named base
7779
char *name;
7880
} typed_ident;
79-
char *ptr_name;
80-
struct {
81-
Stmt *block;
82-
} async;
8381
struct {
8482
Expr *callee;
8583
ExprList args;
@@ -88,25 +86,30 @@ struct Expr {
8886
size_t kw_count;
8987
size_t kw_capacity;
9088
} call;
89+
struct {
90+
Stmt *block;
91+
} async;
92+
struct {
93+
ParamList params;
94+
DeclType return_type;
95+
int return_base; // 0 = parent INT/FLT, 2..64 = named base
96+
Stmt *body;
97+
} lambda;
98+
ExprList tns_items;
99+
struct {
100+
ExprList keys;
101+
ExprList values;
102+
} map_items;
91103
struct {
92104
Expr *target;
93105
ExprList indices;
94-
bool is_map; /* true if angle-bracket indexing '<...>' was used */
106+
bool is_map;
95107
} index;
96108
struct {
97109
Expr *start;
98110
Expr *end;
99111
} range;
100-
struct {
101-
ExprList keys;
102-
ExprList values;
103-
} map_items;
104-
struct {
105-
ParamList params;
106-
DeclType return_type;
107-
Stmt *body;
108-
} lambda;
109-
ExprList tns_items;
112+
char *ptr_name;
110113
} as;
111114
};
112115

@@ -150,12 +153,14 @@ struct Stmt {
150153
struct {
151154
bool has_type;
152155
DeclType decl_type;
156+
int decl_base; // 0 = parent INT/FLT, 2..64 = named base
153157
char *name;
154158
Expr *target;
155159
Expr *value;
156160
} assign;
157161
struct {
158162
DeclType decl_type;
163+
int decl_base; // 0 = parent INT/FLT, 2..64 = named base
159164
char *name;
160165
} decl;
161166
struct {
@@ -183,6 +188,7 @@ struct Stmt {
183188
char *name;
184189
ParamList params;
185190
DeclType return_type;
191+
int return_base; // 0 = parent INT/FLT, 2..64 = named base
186192
Stmt *body;
187193
} func_stmt;
188194
struct {
@@ -221,7 +227,7 @@ Expr *expr_flt(double value, int base, int base_is_nan, int line, int column);
221227
Expr *expr_str(char *value, int line, int column);
222228
Expr *expr_ptr(char *name, int line, int column);
223229
Expr *expr_ident(char *name, int line, int column);
224-
Expr *expr_typed_ident(DeclType decl_type, char *name, int line, int column);
230+
Expr *expr_typed_ident(DeclType decl_type, int decl_base, char *name, int line, int column);
225231
Expr *expr_call(Expr *callee, int line, int column);
226232
void call_kw_add(Expr *call, char *name, Expr *value);
227233
Expr *expr_tns(int line, int column);
@@ -230,19 +236,20 @@ Expr *expr_map(int line, int column);
230236
Expr *expr_index(Expr *target, int line, int column, bool is_map);
231237
Expr *expr_range(Expr *start, Expr *end, int line, int column);
232238
Expr *expr_wildcard(int line, int column);
233-
Expr *expr_lambda(ParamList params, DeclType return_type, Stmt *body, int line, int column);
239+
Expr *expr_lambda(ParamList params, DeclType return_type, int return_base, Stmt *body, int line, int column);
234240
void expr_list_add(ExprList *list, Expr *expr);
235241

236242
Stmt *stmt_block(int line, int column);
237243
Stmt *stmt_async(Stmt *body, int line, int column);
238244
Stmt *stmt_expr(Expr *expr, int line, int column);
239-
Stmt *stmt_assign(bool has_type, DeclType decl_type, char *name, Expr *target, Expr *value, int line, int column);
240-
Stmt *stmt_decl(DeclType decl_type, char *name, 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);
241248
Stmt *stmt_if(Expr *cond, Stmt *then_branch, int line, int column);
242249
Stmt *stmt_while(Expr *cond, Stmt *body, int line, int column);
243250
Stmt *stmt_for(char *counter, Expr *target, Stmt *body, int line, int column);
244251
Stmt *stmt_parfor(char *counter, Expr *target, Stmt *body, int line, int column);
245-
Stmt *stmt_func(char *name, DeclType ret, Stmt *body, int line, int column);
252+
Stmt *stmt_func(char *name, DeclType ret, int return_base, Stmt *body, int line, int column);
246253
Stmt *stmt_return(Expr *value, int line, int column);
247254
Stmt *stmt_pop(Expr *expr, int line, int column);
248255
Stmt *stmt_break(Expr *value, int line, int column);

0 commit comments

Comments
 (0)