summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2019-11-16 14:20:19 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2019-11-16 14:20:19 -0500
commit09af32ffade52ca84943d047db9e2dcecc4ca495 (patch)
treea1d2670f4d36fc37184096fdb16ca0186ab88f91
parent54f1d5bc80117063a1b67f834b65dbb488ddf1c8 (diff)
:@
-rw-r--r--cgen.c71
-rw-r--r--decls_cgen.c44
-rw-r--r--main.c2
-rw-r--r--parse.c64
-rw-r--r--test.toc24
-rw-r--r--typedefs_cgen.c3
-rw-r--r--types.c60
-rw-r--r--types.h25
8 files changed, 224 insertions, 69 deletions
diff --git a/cgen.c b/cgen.c
index 838d6ef..9f5b62c 100644
--- a/cgen.c
+++ b/cgen.c
@@ -412,8 +412,8 @@ static inline void cgen_fn_name(CGenerator *g, FnExpr *f) {
}
}
-/* unless f needs multiple instances, instance can be set to 0 */
-static bool cgen_fn_header(CGenerator *g, FnExpr *f, Location where, I64 instance) {
+/* unless f has const/semi-const args, instance and which_are_const can be set to 0 */
+static bool cgen_fn_header(CGenerator *g, FnExpr *f, Location where, I64 instance, U64 which_are_const) {
bool out_param = cgen_uses_ptr(&f->ret_type);
bool any_params = false;
if (!f->c.name) /* anonymous fn */
@@ -432,8 +432,10 @@ static bool cgen_fn_header(CGenerator *g, FnExpr *f, Location where, I64 instanc
if (!cgen_type_post(g, &f->ret_type, where)) return false;
}
cgen_write(g, "(");
+ int semi_const_idx = 0;
arr_foreach(f->params, Declaration, d) {
- if (!(d->flags & DECL_IS_CONST)) {
+ if (!(d->flags & DECL_IS_CONST) && !((d->flags & DECL_SEMI_CONST)
+ && (which_are_const & (((U64)1) << semi_const_idx++)))) {
long idx = 0;
arr_foreach(d->idents, Identifier, i) {
if (d != f->params || i != d->idents)
@@ -591,10 +593,10 @@ static bool cgen_set_tuple(CGenerator *g, Expression *exprs, Identifier *idents,
cgen_write(g, "%"PRId64, to->call.c.instance);
cgen_write(g, "(");
bool any_args = false;
- bool *constant = to->call.fn->type.fn.constant;
+ Constness *constness = to->call.fn->type.fn.constness;
int i = 0;
arr_foreach(to->call.arg_exprs, Expression, arg) {
- if (!constant || !constant[i]) {
+ if (!constness || !arg_is_const(arg, constness[i])) {
if (any_args)
cgen_write(g, ", ");
any_args = true;
@@ -938,9 +940,9 @@ static bool cgen_expr_pre(CGenerator *g, Expression *e) {
case EXPR_CALL: {
if (!cgen_expr_pre(g, e->call.fn)) return false;
int i = 0;
- bool *constant = e->call.fn->type.fn.constant;
+ Constness *constness = e->call.fn->type.fn.constness;
arr_foreach(e->call.arg_exprs, Expression, arg) {
- if (!constant || !constant[i]) {
+ if (!constness || !arg_is_const(arg, constness[i])) {
if (!cgen_expr_pre(g, arg)) return false;
}
i++;
@@ -961,7 +963,7 @@ static bool cgen_expr_pre(CGenerator *g, Expression *e) {
bool any_args = false;
i = 0;
arr_foreach(e->call.arg_exprs, Expression, arg) {
- if (!constant || !constant[i]) {
+ if (!constness || !arg_is_const(arg, constness[i])) {
if (any_args) cgen_write(g, ", ");
any_args = true;
if (!cgen_expr(g, arg))
@@ -1107,10 +1109,21 @@ static bool cgen_expr(CGenerator *g, Expression *e) {
IdentDecl *idecl = ident_decl(e->ident);
if (idecl && idecl->kind == IDECL_DECL) {
Declaration *d = idecl->decl;
- Value fn_val = d->val;
- FnExpr *fn = fn_val.fn;
- cgen_fn_name(g, fn);
- handled = true;
+ if (d->flags & DECL_IS_CONST) {
+ int index = decl_ident_index(d, e->ident);
+ Value fn_val = *decl_val_at_index(d, index);
+ FnExpr *fn = fn_val.fn;
+ Expression fn_expr;
+
+ fn_expr.kind = EXPR_FN;
+ fn_expr.fn = *fn;
+ fn_expr.flags = EXPR_FOUND_TYPE;
+ fn_expr.type = *decl_type_at_index(d, index);
+
+ if (!cgen_expr(g, &fn_expr))
+ return false;
+ handled = true;
+ }
}
}
if (!handled) {
@@ -1307,9 +1320,9 @@ static bool cgen_expr(CGenerator *g, Expression *e) {
}
cgen_write(g, "(");
bool first_arg = true;
- size_t i = 0;
+ int i = 0;
arr_foreach(e->call.arg_exprs, Expression, arg) {
- if (!fn_type->constant || !fn_type->constant[i]) {
+ if (!fn_type->constness || !arg_is_const(arg, fn_type->constness[i])) {
if (!first_arg)
cgen_write(g, ", ");
first_arg = false;
@@ -1363,9 +1376,10 @@ static bool cgen_expr(CGenerator *g, Expression *e) {
case EXPR_TYPE:
assert(0);
break;
- case EXPR_FN:
- cgen_fn_name(g, &e->fn);
- break;
+ case EXPR_FN: {
+ FnExpr *f = &e->fn;
+ cgen_fn_name(g, f);
+ } break;
case EXPR_SLICE:
cgen_ident_id(g, e->slice.c.id);
break;
@@ -1445,8 +1459,9 @@ static bool cgen_fn(CGenerator *g, FnExpr *f, Location where, I64 instance, Valu
/* see also cgen_defs_expr */
FnExpr *prev_fn = g->fn;
Block *prev_block = g->block;
+ U64 which_are_const = compile_time_args ? compile_time_args->u64 : 0;
fn_enter(f, 0);
- if (!cgen_fn_header(g, f, where, instance))
+ if (!cgen_fn_header(g, f, where, instance, which_are_const))
return false;
g->fn = f;
cgen_write(g, " {");
@@ -1457,8 +1472,12 @@ static bool cgen_fn(CGenerator *g, FnExpr *f, Location where, I64 instance, Valu
}
if (compile_time_args) {
int carg_idx = 0;
+ compile_time_args++; /* move past which_are_const */
+ int semi_const_idx = 0;
arr_foreach(f->params, Declaration, param) {
- if (param->flags & DECL_IS_CONST) {
+ if ((param->flags & DECL_IS_CONST)
+ || ((param->flags & DECL_SEMI_CONST)
+ && (which_are_const & (((U64)1) << semi_const_idx++)))) {
int i = 0;
arr_foreach(param->idents, Identifier, ident) {
Type *type = param->type.kind == TYPE_TUPLE ? &param->type.tuple[i]
@@ -1784,8 +1803,15 @@ static bool cgen_stmt(CGenerator *g, Statement *s) {
static bool cgen_defs_expr(CGenerator *g, Expression *e) {
if (e->kind == EXPR_FN) {
FnExpr *f = &e->fn;
-
- if (e->type.fn.constant) {
+ FnType *fn_type = &e->type.fn;
+ bool any_const = false;
+ if (fn_type->constness) {
+ for (size_t i = 0; i < arr_len(fn_type->types)-1; i++) {
+ if (fn_type->constness[i] == CONSTNESS_YES)
+ any_const = true;
+ }
+ }
+ if (fn_type->constness) {
HashTable *instances = f->c.instances;
if (instances) {
/* generate each instance */
@@ -1798,7 +1824,8 @@ static bool cgen_defs_expr(CGenerator *g, Expression *e) {
}
}
}
- } else {
+ }
+ if (!any_const) {
if (!cgen_fn(g, &e->fn, e->where, 0, NULL))
return false;
}
diff --git a/decls_cgen.c b/decls_cgen.c
index 0e9fff3..6b52291 100644
--- a/decls_cgen.c
+++ b/decls_cgen.c
@@ -8,7 +8,7 @@ static bool cgen_decls_expr(CGenerator *g, Expression *e) {
e->call.c.instance = 0;
assert(e->call.fn->type.kind == TYPE_FN);
FnType *fn_type = &e->call.fn->type.fn;
- if (fn_type->constant) {
+ if (fn_type->constness) {
Value fval;
/* e->call.fn had better be a compile-time constant if it has compile-time arguments */
if (!eval_expr(g->evalr, e->call.fn, &fval))
@@ -20,9 +20,25 @@ static bool cgen_decls_expr(CGenerator *g, Expression *e) {
Value *compile_time_args = NULL;
Type *tuple_types = NULL;
size_t nparams = arr_len(fn_type->types)-1;
+ Value *which_are_const_val = arr_add(&compile_time_args);
+ U64 *which_are_const = &which_are_const_val->u64;
+ Type *u64t = arr_add(&tuple_types);
+ u64t->kind = TYPE_BUILTIN;
+ u64t->flags = TYPE_IS_RESOLVED;
+ u64t->builtin = BUILTIN_U64;
+ *which_are_const = 0;
+ int semi_const_arg_index = 0;
for (size_t i = 0; i < nparams; i++) {
- if (fn_type->constant[i]) {
- Expression *arg = &e->call.arg_exprs[i];
+ Expression *arg = &e->call.arg_exprs[i];
+ if (arg_is_const(arg, fn_type->constness[i])) {
+ if (fn_type->constness[i] == CONSTNESS_SEMI) {
+ if (semi_const_arg_index >= 64) {
+ err_print(e->where, "You can't have more than 64 semi-constant parameters in a function at the moment.");
+ return false;
+ }
+ *which_are_const |= ((U64)1) << semi_const_arg_index;
+ semi_const_arg_index++;
+ }
assert(arg->kind == EXPR_VAL); /* should have been evaluated by types.c */
*(Value *)arr_adda(&compile_time_args, g->allocr) = arg->val;
*(Type *)arr_add(&tuple_types) = arg->type;
@@ -44,7 +60,7 @@ static bool cgen_decls_expr(CGenerator *g, Expression *e) {
bool already_generated_decl = val_hash_table_adda(g->allocr, f->c.instances, tuple, &tuple_type, &instance_number);
if (!already_generated_decl) {
/* generate a copy of this function */
- if (!cgen_fn_header(g, f, e->where, instance_number))
+ if (!cgen_fn_header(g, f, e->where, instance_number, *which_are_const))
return false;
cgen_write(g, ";");
cgen_nl(g);
@@ -58,9 +74,18 @@ static bool cgen_decls_expr(CGenerator *g, Expression *e) {
e->fn.c.name = NULL;
if (!e->fn.c.id)
e->fn.c.id = g->ident_counter++;
- if (!e->type.fn.constant) {
+ bool any_const = false;
+ FnType *fn_type = &e->type.fn;
+ if (fn_type->constness) {
+ for (size_t i = 0; i < arr_len(fn_type->types)-1; i++) {
+ if (fn_type->constness[i] == CONSTNESS_YES)
+ any_const = true;
+ }
+ }
+
+ if (!any_const) {
fn_enter(&e->fn, 0);
- if (!cgen_fn_header(g, &e->fn, e->where, 0))
+ if (!cgen_fn_header(g, &e->fn, e->where, 0, 0))
return false;
cgen_write(g, ";");
cgen_nl(g);
@@ -79,17 +104,18 @@ static bool cgen_decls_block(CGenerator *g, Block *b) {
if (!cgen_block_enter(g, b))
return false;
arr_foreach(b->stmts, Statement, s)
- cgen_decls_stmt(g, s);
+ if (!cgen_decls_stmt(g, s))
+ return false;
cgen_block_exit(g, prev);
return true;
}
static bool cgen_decls_decl(CGenerator *g, Declaration *d) {
if (cgen_fn_is_direct(g, d)) {
+ d->expr.fn.c.name = d->idents[0];
if (!fn_has_any_const_params(&d->expr.fn)) {
- d->expr.fn.c.name = d->idents[0];
fn_enter(&d->expr.fn, 0);
- if (!cgen_fn_header(g, &d->expr.fn, d->where, 0))
+ if (!cgen_fn_header(g, &d->expr.fn, d->where, 0, 0))
return false;
cgen_write(g, ";");
cgen_nl(g);
diff --git a/main.c b/main.c
index e2ec9e4..4686fec 100644
--- a/main.c
+++ b/main.c
@@ -1,7 +1,5 @@
/*
TODO:
-:@
-don't allow pointers to functions with compile-time arguments
type parameters (e.g. fn(foo @ type) {x: foo;})
struct parameters
diff --git a/parse.c b/parse.c
index 9db0ffb..24c56b5 100644
--- a/parse.c
+++ b/parse.c
@@ -1,6 +1,7 @@
static bool parse_expr(Parser *p, Expression *e, Token *end);
static bool parse_stmt(Parser *p, Statement *s);
#define PARSE_DECL_ALLOW_CONST_WITH_NO_EXPR 0x01
+#define PARSE_DECL_ALLOW_SEMI_CONST 0x02
static bool parse_decl(Parser *p, Declaration *d, DeclEndKind ends_with, uint16_t flags);
static bool is_decl(Tokenizer *t);
@@ -174,6 +175,17 @@ static size_t type_to_str_(Type *t, char *buffer, size_t bufsize) {
for (size_t i = 0; i < nparams; i++) {
if (i > 0)
written += str_copy(buffer + written, bufsize - written, ", ");
+ if (t->fn.constness) {
+ switch (t->fn.constness[i]) {
+ case CONSTNESS_NO: break;
+ case CONSTNESS_SEMI:
+ written += str_copy(buffer + written, bufsize - written, ":@");
+ break;
+ case CONSTNESS_YES:
+ written += str_copy(buffer + written, bufsize - written, "@");
+ break;
+ }
+ }
written += type_to_str_(&param_types[i], buffer + written, bufsize - written);
}
written += str_copy(buffer + written, bufsize - written, ")");
@@ -382,6 +394,7 @@ static bool parse_type(Parser *p, Type *type) {
/* function type */
type->kind = TYPE_FN;
type->fn.types = NULL;
+ type->fn.constness = NULL;
t->token++;
if (!token_is_kw(t->token, KW_LPAREN)) {
tokr_err(t, "Expected ( to follow fn.");
@@ -763,7 +776,7 @@ static bool parse_decl_list(Parser *p, Declaration **decls, DeclEndKind decl_end
!token_is_kw(t->token - 1, KW_LBRACE)))) {
first = false;
Declaration *decl = parser_arr_add(p, decls);
- if (!parse_decl(p, decl, decl_end, PARSE_DECL_ALLOW_CONST_WITH_NO_EXPR)) {
+ if (!parse_decl(p, decl, decl_end, PARSE_DECL_ALLOW_CONST_WITH_NO_EXPR | PARSE_DECL_ALLOW_SEMI_CONST)) {
ret = false;
/* skip to end of list */
while (t->token->kind != TOKEN_EOF && !ends_decl(t->token, decl_end))
@@ -808,7 +821,7 @@ static bool parse_fn_expr(Parser *p, FnExpr *f) {
if (!parse_decl_list(p, &f->ret_decls, DECL_END_LBRACE_COMMA))
return false;
arr_foreach(f->ret_decls, Declaration, d) {
- if (d->flags & DECL_IS_CONST) {
+ if ((d->flags & DECL_IS_CONST) || (d->flags & DECL_SEMI_CONST)) {
err_print(d->where, "Named return values cannot be constant.");
return false;
}
@@ -1691,7 +1704,7 @@ static inline bool ends_decl(Token *t, DeclEndKind ends_with) {
}
}
-static bool parse_decl(Parser *p, Declaration *d, DeclEndKind ends_with, uint16_t flags) {
+static bool parse_decl(Parser *p, Declaration *d, DeclEndKind ends_with, U16 flags) {
d->where = p->tokr->token->where;
d->idents = NULL;
Tokenizer *t = p->tokr;
@@ -1711,6 +1724,10 @@ static bool parse_decl(Parser *p, Declaration *d, DeclEndKind ends_with, uint16_
}
if (token_is_kw(t->token, KW_COLON)) {
t->token++;
+ if (token_is_kw(t->token, KW_AT) && (flags & PARSE_DECL_ALLOW_SEMI_CONST)) {
+ t->token++;
+ d->flags |= DECL_SEMI_CONST;
+ }
break;
}
if (token_is_kw(t->token, KW_AT)) {
@@ -2188,3 +2205,44 @@ static inline Type *decl_type_at_index(Declaration *d, int i) {
return d->type.kind == TYPE_TUPLE ? &d->type.tuple[i] : &d->type;
}
+
+static bool expr_is_definitely_const(Expression *e) {
+ switch (e->kind) {
+ case EXPR_LITERAL_FLOAT:
+ case EXPR_LITERAL_INT:
+ case EXPR_LITERAL_CHAR:
+ case EXPR_LITERAL_STR:
+ case EXPR_LITERAL_BOOL:
+ case EXPR_DSIZEOF:
+ case EXPR_DALIGNOF:
+ case EXPR_TYPE:
+ case EXPR_VAL:
+ return true;
+ case EXPR_IF:
+ case EXPR_WHILE:
+ case EXPR_C:
+ case EXPR_NEW:
+ case EXPR_CAST:
+ case EXPR_CALL:
+ case EXPR_BLOCK:
+ case EXPR_TUPLE:
+ case EXPR_EACH:
+ case EXPR_FN:
+ return false;
+ case EXPR_UNARY_OP:
+ return expr_is_definitely_const(e->unary.of);
+ case EXPR_BINARY_OP:
+ return expr_is_definitely_const(e->binary.lhs)
+ && expr_is_definitely_const(e->binary.rhs);
+ case EXPR_SLICE:
+ return expr_is_definitely_const(e->slice.of);
+ case EXPR_IDENT: {
+ IdentDecl *idecl = ident_decl(e->ident);
+ assert(idecl);
+ return idecl->kind == IDECL_DECL
+ && (idecl->decl->flags & DECL_IS_CONST);
+ }
+ }
+ assert(0);
+ return false;
+}
diff --git a/test.toc b/test.toc
index 98e1063..5ae33fd 100644
--- a/test.toc
+++ b/test.toc
@@ -2,19 +2,17 @@ puti @= fn(x: int) {
#C("printf(\"%ld\\n\", (long)x);
");
};
-putf @= fn(x: float) {
- #C("printf(\"%f\\n\", (double)x);
-");
-};
-x,z @= fn(x: int, y @ int) int {
- x+y
-};
+// putf @= fn(x: float) {
+ // #C("printf(\"%f\\n\", (double)x);
+// ");
+// };
+// f@= fn(x: int, y :@ int) int {
+// x+y
+// };
+
+asdf @= fn(x :@= 18) int { x };
main @= fn() {
- puti(x(10, 30));
- a @= x(20, 40);
- puti(a);
- puti(z(10, 30));
- b @= z(20, 40);
- puti(b);
+ something := asdf;
+ puti(something(100));
};
diff --git a/typedefs_cgen.c b/typedefs_cgen.c
index a6453de..77ea7f5 100644
--- a/typedefs_cgen.c
+++ b/typedefs_cgen.c
@@ -5,7 +5,8 @@ static bool typedefs_block(CGenerator *g, Block *b) {
if (!cgen_block_enter(g, b))
return false;
arr_foreach(b->stmts, Statement, s)
- typedefs_stmt(g, s);
+ if (!typedefs_stmt(g, s))
+ return false;
cgen_block_exit(g, prev);
return true;
}
diff --git a/types.c b/types.c
index c90c2d8..bf79774 100644
--- a/types.c
+++ b/types.c
@@ -55,7 +55,16 @@ static bool type_eq(Type *a, Type *b) {
case TYPE_FN: {
if (arr_len(a->fn.types) != arr_len(b->fn.types)) return false;
Type *a_types = a->fn.types, *b_types = b->fn.types;
+ Constness *a_constness = a->fn.constness, *b_constness = b->fn.constness;
for (size_t i = 0; i < arr_len(a->fn.types); i++) {
+ Constness const_a = CONSTNESS_NO, const_b = CONSTNESS_NO;
+ if (a_constness)
+ const_a = a_constness[i];
+ if (b_constness)
+ const_b = b_constness[i];
+ if ((const_a == CONSTNESS_NO && const_b == CONSTNESS_YES)
+ || (const_a == CONSTNESS_YES && const_b == CONSTNESS_NO))
+ return false;
if (!type_eq(&a_types[i], &b_types[i]))
return false;
@@ -177,7 +186,7 @@ static bool type_of_fn(Typer *tr, Expression *e, Type *t) {
FnExpr *f = &e->fn;
t->kind = TYPE_FN;
t->fn.types = NULL;
- t->fn.constant = NULL; /* OPTIM: constant doesn't need to be a dynamic array */
+ t->fn.constness = NULL; /* OPTIM: constant doesn't need to be a dynamic array */
bool has_constant_params = false;
Type *ret_type = typer_arr_add(tr, &t->fn.types);
if (f->ret_decls && f->ret_type.kind == TYPE_VOID /* haven't found return type yet */) {
@@ -215,12 +224,12 @@ static bool type_of_fn(Typer *tr, Expression *e, Type *t) {
if (!types_decl(tr, decl)) return false;
if (!type_resolve(tr, &decl->type, e->where))
return false;
- unsigned is_const = decl->flags & DECL_IS_CONST;
- if (is_const) {
- if (!t->fn.constant) {
+ U32 is_at_all_const = decl->flags & (DECL_IS_CONST | DECL_SEMI_CONST);
+ if (is_at_all_const) {
+ if (!t->fn.constness) {
has_constant_params = true;
for (size_t i = 0; i < idx; i++) {
- *(bool *)typer_arr_add(tr, &t->fn.constant) = false;
+ *(Constness *)typer_arr_add(tr, &t->fn.constness) = CONSTNESS_NO;
}
}
}
@@ -239,7 +248,15 @@ static bool type_of_fn(Typer *tr, Expression *e, Type *t) {
Type *param_type = typer_arr_add(tr, &t->fn.types);
*param_type = decl->type;
if (has_constant_params) {
- *(bool *)typer_arr_add(tr, &t->fn.constant) = is_const != 0;
+ Constness constn;
+ if (decl->flags & DECL_IS_CONST) {
+ constn = CONSTNESS_YES;
+ } else if (decl->flags & DECL_SEMI_CONST) {
+ constn = CONSTNESS_SEMI;
+ } else {
+ constn = CONSTNESS_NO;
+ }
+ *(Constness *)typer_arr_add(tr, &t->fn.constness) = constn;
}
idx++;
}
@@ -563,6 +580,17 @@ static Status type_cast_status(Type *from, Type *to) {
return STATUS_ERR;
}
+static bool arg_is_const(Expression *arg, Constness constness) {
+ switch (constness) {
+ case CONSTNESS_NO: return false;
+ case CONSTNESS_SEMI: return expr_is_definitely_const(arg);
+ case CONSTNESS_YES: return true;
+ }
+ assert(0);
+ return false;
+}
+
+
static bool types_expr(Typer *tr, Expression *e) {
if (e->flags & EXPR_FOUND_TYPE) return true;
Type *t = &e->type;
@@ -999,11 +1027,8 @@ static bool types_expr(Typer *tr, Expression *e) {
}
if (!ret) return false;
- bool any_const = false;
FnType *fn_type = &f->type.fn;
for (size_t i = 0; i < nparams; i++) {
- if (fn_type->constant && fn_type->constant[i])
- any_const = true;
if (!params_set[i]) {
size_t index = 0;
assert(fn_decl); /* we can only miss an arg if we're using named/optional args */
@@ -1036,10 +1061,12 @@ static bool types_expr(Typer *tr, Expression *e) {
}
}
}
- if (any_const) {
+ if (fn_type->constness) {
/* evaluate compile-time arguments */
for (size_t i = 0; i < arr_len(fn_type->types)-1; i++) {
- if (fn_type->constant[i]) {
+ bool should_be_evald = arg_is_const(&new_args[i], fn_type->constness[i]);
+
+ if (should_be_evald) {
Value arg_val;
if (!eval_expr(tr->evalr, &new_args[i], &arg_val)) {
if (tr->evalr->enabled) {
@@ -1048,6 +1075,7 @@ static bool types_expr(Typer *tr, Expression *e) {
return false;
}
new_args[i].kind = EXPR_VAL;
+ new_args[i].flags = 0;
new_args[i].val = arg_val;
i++;
}
@@ -1544,6 +1572,16 @@ static bool types_decl(Typer *tr, Declaration *d) {
success = false;
goto ret;
}
+ } else if (!(d->flags & DECL_IS_CONST) && t->kind == TYPE_FN && t->fn.constness) {
+ for (size_t p = 0; p < arr_len(t->fn.types)-1; p++) {
+ if (t->fn.constness[p] == CONSTNESS_YES) {
+ err_print(d->where, "You can't have a pointer to a function with constant parameters.");
+ success = false;
+ goto ret;
+ }
+ }
+ /* make constness NULL, so that semi-constant parameters turn into non-constant arguments */
+ t->fn.constness = NULL;
}
}
diff --git a/types.h b/types.h
index 3b0b3ba..25a3dbe 100644
--- a/types.h
+++ b/types.h
@@ -313,9 +313,15 @@ typedef struct {
#define TYPE_IS_RESOLVED 0x02
#define TYPE_STRUCT_FOUND_OFFSETS 0x04
+typedef U8 Constness;
+
+#define CONSTNESS_NO ((Constness)0)
+#define CONSTNESS_SEMI ((Constness)1)
+#define CONSTNESS_YES ((Constness)2)
+
typedef struct {
struct Type *types; /* dynamic array [0] = ret_type, [1:] = param_types */
- bool *constant; /* [i] = is param #i constant? if NULL, none are constant. don't use it as a dynamic array, because eventually it might not be. */
+ Constness *constness; /* [i] = constness of param #i. iff no parameters are constant, this is NULL. don't use it as a dynamic array, because eventually it might not be. */
} FnType;
typedef struct Type {
@@ -588,13 +594,16 @@ typedef struct Argument {
Expression val;
} Argument;
-#define DECL_ANNOTATES_TYPE 0x01
-#define DECL_IS_CONST 0x02
-#define DECL_HAS_EXPR 0x04
-#define DECL_FOUND_TYPE 0x08
-#define DECL_ERRORED_ABOUT_SELF_REFERENCE 0x10 /* has there been an error about this decl referencing itself? */
-#define DECL_FOUND_VAL 0x20
-
+enum {
+ DECL_ANNOTATES_TYPE = 0x01,
+ DECL_IS_CONST = 0x02,
+ DECL_SEMI_CONST = 0x04,
+ DECL_HAS_EXPR = 0x08,
+ DECL_FOUND_TYPE = 0x10,
+ DECL_ERRORED_ABOUT_SELF_REFERENCE = 0x20, /* has there been an error about this decl referencing itself? */
+ DECL_FOUND_VAL = 0x40,
+};
+
/* OPTIM: Instead of using dynamic arrays, do two passes. */
typedef struct Declaration {
Location where;