summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cgen.c54
-rw-r--r--decls_cgen.c14
-rw-r--r--eval.c93
-rw-r--r--main.c6
-rw-r--r--parse.c31
-rw-r--r--std/io.toc23
-rw-r--r--test.toc20
-rw-r--r--tokenizer.c4
-rw-r--r--types.c25
-rw-r--r--types.h5
10 files changed, 199 insertions, 76 deletions
diff --git a/cgen.c b/cgen.c
index e33aac9..41d156c 100644
--- a/cgen.c
+++ b/cgen.c
@@ -266,11 +266,11 @@ static inline void cgen_ident_simple(CGenerator *g, Identifier i) {
}
static void cgen_ident(CGenerator *g, Identifier i) {
- if (g->block && (g->block->flags & BLOCK_IS_NMS)) {
+ if (g->block && (g->block->flags & BLOCK_IS_NMS) && !g->fn) {
/* namespace prefix */
cgen_write(g, "%s", g->nms_prefix);
}
- if (i == g->main_ident) {
+ if (i == g->main_ident && ident_decl(i) && ident_decl(i)->scope == NULL) {
/* don't conflict with C's main! */
cgen_write(g, "main__");
} else {
@@ -285,15 +285,21 @@ static inline void cgen_ident_id_to_str(char *buffer, IdentID id) {
snprintf(buffer, 32, "a%lu_", (unsigned long)id);
}
-/* does NOT include __ */
static char *cgen_nms_prefix(CGenerator *g, Namespace *n) {
char *s;
if (n->associated_ident) {
- s = cgen_ident_to_str(n->associated_ident);
+ size_t ident_len = n->associated_ident->len;
+ s = malloc(ident_len + 3);
+ memcpy(s, n->associated_ident->str, ident_len);
+ s[ident_len] = '_';
+ s[ident_len+1] = '_';
+ s[ident_len+2] = '\0';
} else {
- s = malloc(CGEN_IDENT_ID_STR_SIZE);
+ s = calloc(CGEN_IDENT_ID_STR_SIZE + 1, 1);
if (!n->c.id) n->c.id = ++g->ident_counter;
cgen_ident_id_to_str(s, n->c.id);
+ s[strlen(s)] = '_';
+
}
return s;
}
@@ -301,22 +307,17 @@ static char *cgen_nms_prefix(CGenerator *g, Namespace *n) {
static void cgen_nms_enter(CGenerator *g, Namespace *n) {
char *s = cgen_nms_prefix(g, n);
size_t chars_so_far = arr_len(g->nms_prefix) - 1; /* -1 for '\0' byte */
- size_t new_chars = strlen(s);
+ size_t new_chars = strlen(s) + 1; /* + 1 for '\0' byte */
arr_set_len(&g->nms_prefix, chars_so_far + new_chars);
for (size_t i = 0; i < new_chars; ++i) {
g->nms_prefix[i+chars_so_far] = s[i];
}
- *(char *)arr_add(&g->nms_prefix) = '_';
- if (n->associated_ident)
- *(char *)arr_add(&g->nms_prefix) = '_';
- *(char *)arr_add(&g->nms_prefix) = '\0';
free(s);
}
static void cgen_nms_exit(CGenerator *g, Namespace *n) {
char *s = cgen_nms_prefix(g, n);
- bool double_underscore = n->associated_ident != NULL;
- arr_set_len(&g->nms_prefix, arr_len(g->nms_prefix) - strlen(s) - (double_underscore ? 2 : 1));
+ arr_set_len(&g->nms_prefix, arr_len(g->nms_prefix) - strlen(s));
free(s);
}
@@ -549,7 +550,7 @@ static bool cgen_fn_args(CGenerator *g, FnExpr *f, U64 instance, U64 which_are_c
if (!cgen_type_pre(g, type, f->where))
return false;
cgen_write(g, " ");
- cgen_ident(g, *i);
+ cgen_ident_simple(g, *i);
if (!cgen_type_post(g, type, f->where))
return false;
}
@@ -1355,6 +1356,8 @@ static bool cgen_expr(CGenerator *g, Expression *e) {
s = "*"; break;
case BINARY_DIV:
s = "/"; break;
+ case BINARY_MOD:
+ s = "%"; break;
case BINARY_SET:
if (!cgen_set(g, e->binary.lhs, NULL, e->binary.rhs, NULL)) return false;
handled = true;
@@ -1379,6 +1382,8 @@ static bool cgen_expr(CGenerator *g, Expression *e) {
s = "*="; break;
case BINARY_SET_DIV:
s = "/="; break;
+ case BINARY_SET_MOD:
+ s = "%="; break;
case BINARY_AT_INDEX:
cgen_write(g, "(");
switch (e->binary.lhs->type.kind) {
@@ -1413,13 +1418,22 @@ static bool cgen_expr(CGenerator *g, Expression *e) {
handled = true;
break;
case BINARY_DOT: {
-
- cgen_write(g, "(");
- cgen_expr(g, e->binary.lhs);
- bool is_ptr = e->binary.lhs->type.kind == TYPE_PTR;
- cgen_write(g, is_ptr ? "->" :".");
- cgen_ident_simple(g, e->binary.dot.field->name);
- cgen_write(g, ")");
+ Type *struct_type = &e->binary.lhs->type;
+ if (struct_type->kind == TYPE_PTR) struct_type = struct_type->ptr;
+ if (struct_type->kind == TYPE_STRUCT) {
+ cgen_write(g, "(");
+ cgen_expr(g, e->binary.lhs);
+ bool is_ptr = e->binary.lhs->type.kind == TYPE_PTR;
+ cgen_write(g, is_ptr ? "->" :".");
+ cgen_ident_simple(g, e->binary.dot.field->name);
+ cgen_write(g, ")");
+ } else {
+ assert(type_is_builtin(struct_type, BUILTIN_NMS));
+ char *prefix = cgen_nms_prefix(g, e->binary.lhs->val.nms);
+ cgen_write(g, "%s", prefix);
+ cgen_ident_simple(g, e->binary.rhs->ident);
+ free(prefix);
+ }
handled = true;
} break;
}
diff --git a/decls_cgen.c b/decls_cgen.c
index f815c13..797443d 100644
--- a/decls_cgen.c
+++ b/decls_cgen.c
@@ -197,7 +197,7 @@ static bool cgen_decls_decl(CGenerator *g, Declaration *d) {
if (!cgen_decls_expr(g, &d->expr))
return false;
}
- if (g->block == NULL && g->fn == NULL) {
+ if ((g->block == NULL || (g->block->flags & BLOCK_IS_NMS)) && g->fn == NULL) {
for (int i = 0, n_idents = (int)arr_len(d->idents); i < n_idents; ++i) {
Identifier ident = d->idents[i];
Type *type = decl_type_at_index(d, i);
@@ -209,6 +209,18 @@ static bool cgen_decls_decl(CGenerator *g, Declaration *d) {
cgen_ident(g, ident);
if (!cgen_type_post(g, type, d->where))
return false;
+ if (g->block) {
+ assert(g->block->flags & BLOCK_IS_NMS);
+ if (d->flags & DECL_HAS_EXPR) {
+ Value *val = decl_val_at_index(d, i);
+ cgen_write(g, " = ");
+ if (!cgen_val(g, *val, type, d->where))
+ return false;
+ } else {
+ cgen_write(g, " = ");
+ cgen_zero_value(g, type);
+ }
+ }
cgen_write(g, ";");
cgen_nl(g);
}
diff --git a/eval.c b/eval.c
index 635c93d..a70a1f8 100644
--- a/eval.c
+++ b/eval.c
@@ -734,45 +734,69 @@ static bool eval_expr_ptr_at_index(Evaluator *ev, Expression *e, void **ptr, Typ
return eval_val_ptr_at_index(e->where, &arr, i, ltype, ptr, type);
}
+static bool eval_address_of_ident(Identifier i, Type *type, Location where, void **ptr) {
+ IdentDecl *id = ident_decl(i);
+ if (!(id->flags & IDECL_HAS_VAL)) {
+ if (id->kind == IDECL_DECL) {
+ Declaration *decl = id->decl;
+ if (!(decl->flags & DECL_IS_CONST) || !(decl->flags & DECL_FOUND_VAL)) goto runtime_var;
+ id->val = decl->val;
+ id->flags |= IDECL_HAS_VAL;
+ } else {
+ runtime_var:
+ err_print(where, "Cannot take address of run time variable at compile time.");
+ return false;
+ }
+ }
+ if (type->kind == TYPE_ARR)
+ *ptr = id->val.arr; /* point directly to data */
+ else if (type->kind == TYPE_STRUCT)
+ *ptr = id->val.struc;
+ else
+ *ptr = &id->val;
+ return true;
+}
+
static void *eval_ptr_to_struct_field(Evaluator *ev, Expression *dot_expr) {
Type *struct_type = &dot_expr->binary.lhs->type;
bool is_ptr = struct_type->kind == TYPE_PTR;
if (is_ptr) {
struct_type = struct_type->ptr;
}
- assert(struct_type->kind == TYPE_STRUCT);
- eval_struct_find_offsets(struct_type->struc);
+ if (struct_type->kind == TYPE_STRUCT) {
+ eval_struct_find_offsets(struct_type->struc);
- Value struc;
- if (!eval_expr(ev, dot_expr->binary.lhs, &struc))
- return NULL;
- void *struc_data;
- if (is_ptr) {
- struc_data = struc.ptr;
- if (struc_data == NULL) {
- err_print(dot_expr->where, "Attempt to dereference NULL pointer.");
+ Value struc;
+ if (!eval_expr(ev, dot_expr->binary.lhs, &struc))
return NULL;
+ void *struc_data;
+ if (is_ptr) {
+ struc_data = struc.ptr;
+ if (struc_data == NULL) {
+ err_print(dot_expr->where, "Attempt to dereference NULL pointer.");
+ return NULL;
+ }
+ } else {
+ struc_data = struc.struc;
}
+ return (char *)struc_data + dot_expr->binary.dot.field->offset;
} else {
- struc_data = struc.struc;
+ void *ptr;
+ assert(type_is_builtin(struct_type, BUILTIN_NMS));
+ Identifier translated = ident_translate(dot_expr->binary.rhs->ident, &dot_expr->binary.lhs->val.nms->idents);
+ if (!eval_address_of_ident(translated, &dot_expr->type, dot_expr->where, &ptr)) {
+ return NULL;
+ }
+ return ptr;
}
- return (char *)struc_data + dot_expr->binary.dot.field->offset;
+
}
static bool eval_address_of(Evaluator *ev, Expression *e, void **ptr) {
switch (e->kind) {
case EXPR_IDENT: {
- IdentDecl *id = ident_decl(e->ident);
- if (!(id->flags & IDECL_HAS_VAL)) {
- err_print(e->where, "Cannot take address of run time variable at compile time.");
+ if (!eval_address_of_ident(e->ident, &e->type, e->where, ptr))
return false;
- }
- if (e->type.kind == TYPE_ARR)
- *ptr = id->val.arr; /* point directly to data */
- else if (e->type.kind == TYPE_STRUCT)
- *ptr = id->val.struc;
- else
- *ptr = &id->val;
} break;
case EXPR_UNARY_OP:
switch (e->unary.op) {
@@ -799,10 +823,10 @@ static bool eval_address_of(Evaluator *ev, Expression *e, void **ptr) {
Value struc;
if (!eval_expr(ev, e->binary.lhs, &struc))
return false;
+
*ptr = eval_ptr_to_struct_field(ev, e);
if (!*ptr)
return false;
- return true;
} break;
default: assert(0); return false;
}
@@ -894,7 +918,7 @@ static void eval_numerical_bin_op(Value lhs, Type *lhs_type, BinaryOp op, Value
case BUILTIN_##up: \
out->low = (up)(lhs.low op rhs.low); break
-#define eval_binary_op_nums(builtin, op) \
+#define eval_binary_op_ints(builtin, op) \
eval_binary_op_one(i8, I8, op); \
eval_binary_op_one(i16, I16, op); \
eval_binary_op_one(i32, I32, op); \
@@ -902,7 +926,10 @@ static void eval_numerical_bin_op(Value lhs, Type *lhs_type, BinaryOp op, Value
eval_binary_op_one(u8, U8, op); \
eval_binary_op_one(u16, U16, op); \
eval_binary_op_one(u32, U32, op); \
- eval_binary_op_one(u64, U64, op); \
+ eval_binary_op_one(u64, U64, op);
+
+#define eval_binary_op_nums(builtin, op) \
+ eval_binary_op_ints(builtin, op); \
eval_binary_op_one(f32, F32, op); \
eval_binary_op_one(f64, F64, op)
@@ -916,6 +943,15 @@ static void eval_numerical_bin_op(Value lhs, Type *lhs_type, BinaryOp op, Value
default: assert(0); break; \
}
+#define eval_binary_op_ints_only(op) \
+ val_cast(&lhs, lhs_type, &lhs, out_type); \
+ val_cast(&rhs, rhs_type, &rhs, out_type); \
+ assert(out_type->kind == TYPE_BUILTIN); \
+ switch (builtin) { \
+ eval_binary_op_ints(builtin, op); \
+ default: assert(0); break; \
+ }
+
#define eval_binary_bool_op_one(low, up, op) \
case BUILTIN_##up: \
@@ -974,6 +1010,8 @@ static void eval_numerical_bin_op(Value lhs, Type *lhs_type, BinaryOp op, Value
eval_binary_op_nums_only(*); break;
case BINARY_DIV:
eval_binary_op_nums_only(/); break;
+ case BINARY_MOD:
+ eval_binary_op_ints_only(%); break;
case BINARY_LT:
eval_binary_bool_op(<); break;
case BINARY_LE:
@@ -1194,6 +1232,7 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) {
case BINARY_SUB:
case BINARY_MUL:
case BINARY_DIV:
+ case BINARY_MOD:
case BINARY_LT:
case BINARY_LE:
case BINARY_GT:
@@ -1208,13 +1247,15 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) {
case BINARY_SET_ADD:
case BINARY_SET_SUB:
case BINARY_SET_MUL:
- case BINARY_SET_DIV: {
+ case BINARY_SET_DIV:
+ case BINARY_SET_MOD: {
BinaryOp subop = (BinaryOp)0;
switch (e->binary.op) {
case BINARY_SET_ADD: subop = BINARY_ADD; break;
case BINARY_SET_SUB: subop = BINARY_SUB; break;
case BINARY_SET_MUL: subop = BINARY_MUL; break;
case BINARY_SET_DIV: subop = BINARY_DIV; break;
+ case BINARY_SET_MOD: subop = BINARY_MOD; break;
default: assert(0);
}
eval_numerical_bin_op(lhs, &e->binary.lhs->type, subop, rhs, &e->binary.rhs->type, v, &e->binary.lhs->type);
diff --git a/main.c b/main.c
index 9cd967f..6f1ac55 100644
--- a/main.c
+++ b/main.c
@@ -18,14 +18,16 @@
/*
TODO:
-namespace
try to remember why arr_set_len doesn't shrink, then write that reason there
+make eval_ptr_to_struct_field return a bool
nms["foo"]
-make sure nms {foo:= 7; } works for cgen
make sure #export still works properly
fix cgen_ident_to_str for unicode idents
check for leaks
---
+nice syntax for importing something into a namespace
+run stuff at compile time without assigning it to a constant
+#compile_only declarations
constants in structs
#if
diff --git a/parse.c b/parse.c
index 3d923f5..390624c 100644
--- a/parse.c
+++ b/parse.c
@@ -80,6 +80,7 @@ static const char *binary_op_to_str(BinaryOp b) {
case BINARY_SET_SUB: return "-=";
case BINARY_SET_MUL: return "*=";
case BINARY_SET_DIV: return "/=";
+ case BINARY_SET_MOD: return "%=";
case BINARY_AT_INDEX: return "[]";
case BINARY_LT: return "<";
case BINARY_LE: return "<=";
@@ -88,6 +89,7 @@ static const char *binary_op_to_str(BinaryOp b) {
case BINARY_EQ: return "==";
case BINARY_NE: return "!=";
case BINARY_DOT: return ".";
+ case BINARY_MOD: return "%";
}
assert(0);
return "";
@@ -931,6 +933,7 @@ static int op_precedence(Keyword op) {
case KW_MINUS_EQ:
case KW_ASTERISK_EQ:
case KW_SLASH_EQ:
+ case KW_PERCENT_EQ:
return 0;
case KW_COMMA: return 1;
case KW_LT: return 3;
@@ -944,6 +947,7 @@ static int op_precedence(Keyword op) {
case KW_AMPERSAND: return 25;
case KW_ASTERISK: return 30;
case KW_SLASH: return 40;
+ case KW_PERCENT: return 45;
case KW_EXCLAMATION: return 50;
case KW_DEL: return 1000;
default: return NOT_AN_OP;
@@ -1501,6 +1505,15 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
case KW_MINUS:
op = BINARY_SUB;
break;
+ case KW_ASTERISK:
+ op = BINARY_MUL;
+ break;
+ case KW_SLASH:
+ op = BINARY_DIV;
+ break;
+ case KW_PERCENT:
+ op = BINARY_MOD;
+ break;
case KW_EQ_EQ:
op = BINARY_EQ;
break;
@@ -1534,11 +1547,8 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
case KW_SLASH_EQ:
op = BINARY_SET_DIV;
break;
- case KW_ASTERISK:
- op = BINARY_MUL;
- break;
- case KW_SLASH:
- op = BINARY_DIV;
+ case KW_PERCENT_EQ:
+ op = BINARY_SET_MOD;
break;
case KW_AMPERSAND:
case KW_EXCLAMATION:
@@ -2021,7 +2031,7 @@ static bool parse_stmt(Parser *p, Statement *s, bool *was_a_statement) {
case KW_SEMICOLON:
*was_a_statement = false;
++t->token;
- return true;
+ goto success;
case KW_RETURN: {
s->kind = STMT_RET;
++t->token;
@@ -2029,7 +2039,7 @@ static bool parse_stmt(Parser *p, Statement *s, bool *was_a_statement) {
if (token_is_kw(t->token, KW_SEMICOLON)) {
/* return with no expr */
++t->token;
- return true;
+ goto success;
}
s->ret.flags |= RET_HAS_EXPR;
Token *end = expr_find_end(p, 0);
@@ -2060,7 +2070,7 @@ static bool parse_stmt(Parser *p, Statement *s, bool *was_a_statement) {
return false;
}
++t->token;
- return true;
+ goto success;
} break;
default:
break;
@@ -2079,7 +2089,7 @@ static bool parse_stmt(Parser *p, Statement *s, bool *was_a_statement) {
tokr_skip_to_eof(t);
return false;
}
- bool success = parse_expr(p, &s->expr, end);
+ bool valid = parse_expr(p, &s->expr, end);
/* go past end of expr regardless of whether successful or not */
if (token_is_kw(end, KW_SEMICOLON)) {
@@ -2089,8 +2099,9 @@ static bool parse_stmt(Parser *p, Statement *s, bool *was_a_statement) {
t->token = end;
}
- if (!success) return false;
+ if (!valid) return false;
}
+ success:
s->where.end = t->token;
return true;
}
diff --git a/std/io.toc b/std/io.toc
index dab2aea..51cfd76 100644
--- a/std/io.toc
+++ b/std/io.toc
@@ -29,6 +29,25 @@ stdout_fwrite ::= fn(data: &u8, size: u64, nmemb: u64) {
};
puts ::= fn(x: []char) {
- stdout_fwrite(&x[0] as &u8, 1, x.len as u64);
- toc_putchar('\n');
+ stdout_fwrite(&x[0] as &u8, 1, x.len as u64);
+ toc_putchar('\n');
};
+
+puti ::= fn(x: int) {
+ if x < 0 {
+ toc_putchar('-');
+ // NOTE: don't do x = -x; here to make sure I64_MIN works
+ }
+ abs ::= fn(x: int) int { if x < 0 { -x } else { x } };
+ scan_digit := 1000000000000000000;
+ started := false;
+ while scan_digit > 0 {
+ digit := abs((x / scan_digit) % 10);
+ if digit > 0 { started = true; }
+ if started {
+ toc_putchar((('0' as int) + digit) as char);
+ }
+ scan_digit /= 10;
+ }
+ toc_putchar('\n');
+}; \ No newline at end of file
diff --git a/test.toc b/test.toc
index 206d903..7c662e0 100644
--- a/test.toc
+++ b/test.toc
@@ -1,10 +1,16 @@
+n ::= nms {
+ x := 1;
+ counter ::= fn() int { x += 1; x };
+};
+
main ::= fn() {
- x ::= nms {
- f ::= fn() {
-
- };
- };
- // x.g();
-}; \ No newline at end of file
+ a := counter();
+ b := counter();
+ counter();
+ c := counter();
+ puti(a);
+ puti(b);
+ puti(c);
+};
diff --git a/tokenizer.c b/tokenizer.c
index b422f9e..723a4b3 100644
--- a/tokenizer.c
+++ b/tokenizer.c
@@ -5,9 +5,9 @@
*/
static const char *const keywords[KW_COUNT] =
{";", ":", ",", "(", ")", "{", "}", "[", "]", "==",
- "+=", "-=", "*=", "/=",
+ "+=", "-=", "*=", "/=", "%=",
"!=", "<=", "<", ">=", ">",
- "+", "-", "*", "!", "&", "/", "..", ".",
+ "+", "-", "*", "!", "&", "/", "%", "..", ".",
"=",
"if", "elif", "else", "while", "for", "return", "fn", "as",
"new", "del", "struct",
diff --git a/types.c b/types.c
index 5ba03a3..1bc9d5d 100644
--- a/types.c
+++ b/types.c
@@ -382,9 +382,10 @@ static bool type_of_ident(Typer *tr, Location where, Identifier i, Type *t) {
case IDECL_DECL: {
Declaration *d = decl->decl;
bool captured = false;
- if (decl->scope != NULL) {
+ if (decl->scope != NULL && !(decl->scope->flags & BLOCK_IS_NMS)) {
+ Block *decl_scope = decl->scope;
/* go back through scopes */
- for (Block **block = arr_last(tr->blocks); *block && *block != decl->scope; --block) {
+ for (Block **block = arr_last(tr->blocks); *block && *block != decl_scope; --block) {
if ((*block)->flags & BLOCK_IS_FN) {
captured = true;
break;
@@ -1855,6 +1856,7 @@ static bool types_expr(Typer *tr, Expression *e) {
case BINARY_SET_SUB:
case BINARY_SET_MUL:
case BINARY_SET_DIV:
+ case BINARY_SET_MOD:
if (!expr_must_lval(e->binary.lhs)) {
return false;
}
@@ -1863,6 +1865,7 @@ static bool types_expr(Typer *tr, Expression *e) {
case BINARY_SUB:
case BINARY_MUL:
case BINARY_DIV:
+ case BINARY_MOD:
case BINARY_LT:
case BINARY_GT:
case BINARY_LE:
@@ -1936,6 +1939,11 @@ static bool types_expr(Typer *tr, Expression *e) {
/* lhs flexible, rhs ? */
*t = *rhs_type;
}
+ if ((o == BINARY_MOD || o == BINARY_SET_MOD)
+ && type_builtin_is_float(t->builtin)) {
+ err_print(e->where, "Cannot use operator % on floating-point numbers.");
+ valid = false;
+ }
} break;
}
}
@@ -2056,6 +2064,8 @@ static bool types_expr(Typer *tr, Expression *e) {
if (!eval_expr(tr->evalr, lhs, &nms_val))
return false;
Namespace *nms = nms_val.nms;
+ lhs->kind = EXPR_VAL;
+ lhs->val.nms = nms;
Identifier translated = ident_translate(rhs->ident, &nms->idents);
if (!translated) {
char *s = ident_to_str(rhs->ident);
@@ -2151,7 +2161,8 @@ static bool types_block(Typer *tr, Block *b, U16 flags) {
bool success = true;
if (!typer_block_enter(tr, b))
return false;
-
+ if (flags & TYPES_BLOCK_NAMESPACE)
+ b->flags |= BLOCK_IS_NMS; /* do this after typer_block_enter because otherwise it won't actually enter the block */
arr_foreach(b->stmts, Statement, s) {
if (!types_stmt(tr, s)) {
success = false;
@@ -2185,7 +2196,6 @@ static bool types_block(Typer *tr, Block *b, U16 flags) {
ret:
if (flags & TYPES_BLOCK_NAMESPACE) {
/* don't exit block because we don't want to have to re-enter each time we grab something from the namespace */
- b->flags |= BLOCK_IS_NMS;
arr_remove_last(&tr->blocks);
tr->block = *(Block **)arr_last(tr->blocks);
} else {
@@ -2241,7 +2251,10 @@ static bool types_decl(Typer *tr, Declaration *d) {
d->type = d->expr.type;
d->type.flags &= (TypeFlags)~(TypeFlags)TYPE_IS_FLEXIBLE; /* x := 5; => x is not flexible */
}
- if ((d->flags & DECL_IS_CONST) || (tr->block == NULL && tr->fn == NULL)) {
+ bool need_value = (d->flags & DECL_IS_CONST) ||
+ ((tr->block == NULL || (tr->block->flags & BLOCK_IS_NMS)) && tr->fn == NULL);
+
+ if (need_value) {
if (!(d->flags & DECL_FOUND_VAL)) {
Value val;
if (!eval_expr(tr->evalr, &d->expr, &val)) {
@@ -2328,7 +2341,7 @@ static bool types_decl(Typer *tr, Declaration *d) {
goto ret;
}
}
- if (n_idents == 1 && d->expr.kind == EXPR_NMS) {
+ if (n_idents == 1 && (d->flags & DECL_HAS_EXPR) && d->expr.kind == EXPR_NMS) {
bool is_at_top_level = true;
typedef Block *BlockPtr;
arr_foreach(tr->blocks, BlockPtr, b) {
diff --git a/types.h b/types.h
index ba972a5..a9d7a2f 100644
--- a/types.h
+++ b/types.h
@@ -254,6 +254,7 @@ typedef enum {
KW_MINUS_EQ,
KW_ASTERISK_EQ,
KW_SLASH_EQ,
+ KW_PERCENT_EQ,
KW_NE,
KW_LE,
KW_LT,
@@ -265,6 +266,7 @@ typedef enum {
KW_EXCLAMATION,
KW_AMPERSAND,
KW_SLASH,
+ KW_PERCENT,
KW_DOTDOT,
KW_DOT,
KW_EQ,
@@ -532,10 +534,12 @@ typedef enum {
BINARY_SUB,
BINARY_MUL,
BINARY_DIV,
+ BINARY_MOD,
BINARY_SET_ADD, /* e.g. x += y */
BINARY_SET_SUB,
BINARY_SET_MUL,
BINARY_SET_DIV,
+ BINARY_SET_MOD,
BINARY_GT,
BINARY_LT,
BINARY_GE,
@@ -899,6 +903,7 @@ typedef struct Typer {
/* for checking for problematic struct circular dependencies */
bool *is_reference_stack;
ParsedFile *parsed_file;
+ Namespace *nms;
} Typer;
typedef struct CGenerator {