summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cgen.c23
-rw-r--r--copy.c31
-rw-r--r--decls_cgen.c7
-rw-r--r--instance_table.c1
-rw-r--r--parse.c29
-rw-r--r--sdecls_cgen.c11
-rw-r--r--test.toc15
-rw-r--r--types.c82
-rw-r--r--types.h57
9 files changed, 169 insertions, 87 deletions
diff --git a/cgen.c b/cgen.c
index 7628bd2..27cf651 100644
--- a/cgen.c
+++ b/cgen.c
@@ -338,6 +338,19 @@ static bool cgen_uses_ptr(Type *t) {
return false;
}
+static void cgen_struct_name(CGenerator *g, StructDef *sdef) {
+ if (sdef->name) {
+ cgen_ident(g, sdef->name);
+ } else {
+ assert(sdef->c.id);
+ cgen_ident_id(g, sdef->c.id);
+ }
+ if (sdef->instance_id) {
+ possibly_static_assert(sizeof sdef->instance_id == 8);
+ cgen_write(g, U64_FMT, sdef->instance_id);
+ }
+}
+
static bool cgen_type_pre(CGenerator *g, Type *t, Location where) {
assert(t->flags & TYPE_IS_RESOLVED);
switch (t->kind) {
@@ -387,13 +400,7 @@ static bool cgen_type_pre(CGenerator *g, Type *t, Location where) {
return false;
case TYPE_STRUCT:
cgen_write(g, "struct ");
- if (t->struc->name) {
- cgen_ident(g, t->struc->name);
- } else if (t->struc->c.id) {
- cgen_ident_id(g, t->struc->c.id);
- } else {
- assert(0);
- }
+ cgen_struct_name(g, t->struc);
break;
case TYPE_TUPLE:
case TYPE_EXPR:
@@ -1591,7 +1598,7 @@ static bool cgen_expr(CGenerator *g, Expression *e) {
case BUILTIN_SIZEOF_SIZE_T:
case BUILTIN_TSIZEOF_SIZE_T: {
Value val = get_builtin_val(e->builtin.which.val);
- cgen_write(g, "%"I64_FMT, val.i64);
+ cgen_write(g, I64_FMT, val.i64);
} break;
}
break;
diff --git a/copy.c b/copy.c
index be82036..3c60c25 100644
--- a/copy.c
+++ b/copy.c
@@ -76,6 +76,25 @@ static void copy_val_full(Copier *c, Value *out, Value *in, Type *t) {
}
}
+static void copy_struct(Copier *c, StructDef *out, StructDef *in) {
+ *out = *in;
+ size_t nfields = arr_len(in->fields);
+ out->fields = NULL;
+
+ arr_set_lena(&out->fields, nfields, c->allocr);
+ for (size_t i = 0; i < nfields; ++i) {
+ Field *fout = &out->fields[i];
+ Field *fin = &in->fields[i];
+ *fout = *fin;
+ copy_type(c, &fout->type, &fin->type);
+ }
+ size_t nparams = arr_len(in->params);
+ out->params = NULL;
+ arr_set_lena(&out->params, nparams, c->allocr);
+ for (size_t i = 0; i < nparams; ++i) {
+ copy_decl(c, &out->params[i], &in->params[i]);
+ }
+}
/* works on unresolved and resolved types (for inference) */
static void copy_type(Copier *c, Type *out, Type *in) {
@@ -127,17 +146,7 @@ static void copy_type(Copier *c, Type *out, Type *in) {
only one thing can point to a given StructDef
*/
out->struc = allocr_malloc(c->allocr, sizeof *out->struc);
- *out->struc = *in->struc;
- size_t nfields = arr_len(in->struc->fields);
- out->struc->fields = NULL;
-
- arr_set_lena(&out->struc->fields, nfields, c->allocr);
- for (size_t i = 0; i < nfields; ++i) {
- Field *fout = &out->struc->fields[i];
- Field *fin = &in->struc->fields[i];
- *fout = *fin;
- copy_type(c, &fout->type, &fin->type);
- }
+ copy_struct(c, out->struc, in->struc);
}
} break;
}
diff --git a/decls_cgen.c b/decls_cgen.c
index 61c93e8..2c6fc63 100644
--- a/decls_cgen.c
+++ b/decls_cgen.c
@@ -15,12 +15,7 @@ static bool cgen_decls_type(CGenerator *g, Type *type) {
if (!(sdef->flags & STRUCT_DEF_CGEN_DEFINED)) {
/* generate struct definition */
cgen_write(g, "struct ");
- if (sdef->name) {
- cgen_ident(g, sdef->name);
- } else {
- assert(sdef->c.id);
- cgen_ident_id(g, sdef->c.id);
- }
+ cgen_struct_name(g, sdef);
cgen_write(g, "{");
cgen_nl(g);
++g->indent_lvl;
diff --git a/instance_table.c b/instance_table.c
index 0f8948a..58dc635 100644
--- a/instance_table.c
+++ b/instance_table.c
@@ -283,6 +283,7 @@ static bool val_eq(Value u, Value v, Type *t) {
/*
if already_exists is not NULL, this will create the instance if it does not exist,
and set already_exists accordingly
+ make sure v's data remains valid
*/
/* OPTIM: store instances in a block array (remember that the pointers need to stay valid!) */
static Instance *instance_table_adda(Allocator *a, HashTable *h, Value v, Type *t,
diff --git a/parse.c b/parse.c
index 67a9233..8bd56fb 100644
--- a/parse.c
+++ b/parse.c
@@ -599,37 +599,43 @@ static bool parse_type(Parser *p, Type *type) {
struc->params = NULL;
struc->where = parser_mk_loc(p);
struc->where.start = t->token;
-
+ memset(&struc->scope, 0, sizeof struc->scope);
+ idents_create(&struc->scope.idents, p->allocr, &struc->scope);
+ memset(&struc->instances, 0, sizeof struc->instances);
+
+ Block *prev_block = p->block;
+ p->block = &struc->scope;
+
++t->token;
if (token_is_kw(t->token, KW_LPAREN)) {
++t->token;
if (!parse_decl_list(p, &struc->params, DECL_END_RPAREN_COMMA))
- return false;
+ goto struct_fail;
}
if (!token_is_kw(t->token, KW_LBRACE)) {
tokr_err(t, "Expected { to follow struct.");
- return false;
+ goto struct_fail;
}
++t->token;
{
while (!token_is_kw(t->token, KW_RBRACE)) {
Declaration field_decl;
if (!parse_decl(p, &field_decl, DECL_END_SEMICOLON, 0)) {
- return false;
+ goto struct_fail;
}
if (field_decl.flags & DECL_IS_CONST) {
/* TODO */
err_print(field_decl.where, "Constant struct members are not supported (yet).");
- return false;
+ goto struct_fail;
}
if ((field_decl.flags & DECL_FOREIGN) && !(field_decl.flags & DECL_IS_CONST)) {
err_print(field_decl.where, "Non-constant struct members cannot be foreign.");
- return false;
+ goto struct_fail;
}
if (field_decl.flags & DECL_HAS_EXPR) {
err_print(field_decl.where, "struct members cannot have initializers.");
- return false;
+ goto struct_fail;
}
long idx = 0;
arr_foreach(field_decl.idents, Identifier, fident) {
@@ -643,7 +649,14 @@ static bool parse_type(Parser *p, Type *type) {
++t->token;
struc->where.end = t->token;
}
- } break;
+ p->block = prev_block;
+ break;
+
+ struct_fail:
+ p->block = prev_block;
+ return false;
+ }
+
default:
goto type_expr;
}
diff --git a/sdecls_cgen.c b/sdecls_cgen.c
index 83c978e..a146eb2 100644
--- a/sdecls_cgen.c
+++ b/sdecls_cgen.c
@@ -20,13 +20,10 @@ static bool cgen_sdecls_type(CGenerator *g, Type *type) {
/* we've already done this */
} else {
cgen_write(g, "struct ");
- if (sdef->name) {
- cgen_ident(g, sdef->name);
- } else {
- IdentID id = ++g->ident_counter;
- cgen_ident_id(g, id);
- sdef->c.id = id;
- }
+ if (!sdef->name) {
+ sdef->c.id = ++g->ident_counter;
+ }
+ cgen_struct_name(g, sdef);
cgen_write(g, ";");
cgen_nl(g);
sdef->flags |= STRUCT_DEF_CGEN_DECLARED;
diff --git a/test.toc b/test.toc
index 4133e4a..3dabdc3 100644
--- a/test.toc
+++ b/test.toc
@@ -1,11 +1,14 @@
-// io ::= nms {
- // #include "std/io.toc";
-// };
+io ::= nms {
+ #include "std/io.toc";
+};
-foo ::= struct(t::Type,u::Type) {
- x: t;
+Arr ::= struct(t::Type) {
+ data: []t;
};
main ::= fn() {
- foo(u = int, u = float);
+ x:Arr(int);
+ x.data = new(int, 10);
+ x.data[0] = 17;
+ io.puti(x.data[0]);
}; \ No newline at end of file
diff --git a/types.c b/types.c
index a800865..be72a85 100644
--- a/types.c
+++ b/types.c
@@ -571,17 +571,20 @@ static bool type_resolve_(Typer *tr, Type *t, Location where, bool is_reference)
if (!type_resolve_(tr, t->slice, where, true))
return false;
break;
- case TYPE_STRUCT:
- if (t->struc->params) {
- err_print(where, "Expected arguments to structure.");
- info_print(t->struc->where, "Structure was declared here.");
- return false;
- }
- arr_foreach(t->struc->fields, Field, f) {
- if (!type_resolve_(tr, &f->type, where, is_reference))
- return false;
+ case TYPE_STRUCT: {
+ if (!(t->struc->flags & STRUCT_DEF_RESOLVED)) {
+ typer_block_enter(tr, &t->struc->scope);
+ arr_foreach(t->struc->fields, Field, f) {
+ if (!type_resolve_(tr, &f->type, where, is_reference)) {
+ typer_block_exit(tr);
+ return false;
+ }
+ }
+ typer_block_exit(tr);
+ t->struc->instance_id = 0;
+ t->struc->flags |= STRUCT_DEF_RESOLVED;
}
- break;
+ } break;
case TYPE_EXPR: {
Value typeval;
*(bool *)arr_add(&tr->is_reference_stack) = is_reference;
@@ -1436,8 +1439,9 @@ static bool types_expr(Typer *tr, Expression *e) {
it would be nice if this code and the code for arguments to normal functions
used the same stuff for named arguments, etc.
*/
- Value *arg_vals = err_malloc(nparams * sizeof *arg_vals);
- Type *arg_types = err_malloc(nparams * sizeof *arg_types);
+ Value *arg_vals = typer_malloc(tr, nparams * sizeof *arg_vals);
+ Type *arg_types = NULL;
+ arr_set_len(&arg_types, nparams);
U8 *params_set = err_calloc(1, nparams);
int p = 0; /* sequential parameter */
@@ -1483,13 +1487,54 @@ static bool types_expr(Typer *tr, Expression *e) {
for (size_t i = 0; i < nparams; ++i)
print_val(arg_vals[i], arg_types + i);
-
- /* TODO: look up args in instance table, etc. */
-
- free(arg_vals);
- free(arg_types);
+
+ HashTable *table = &base->struc->instances;
+ bool already_exists;
+ Value args_val = {0};
+ Type args_type = {0};
+ args_val.tuple = arg_vals;
+ args_type.tuple = arg_types;
+ args_type.kind = TYPE_TUPLE;
+ args_type.flags = TYPE_IS_RESOLVED;
+ Instance *inst = instance_table_adda(tr->allocr, table, args_val, &args_type, &already_exists);
+ if (!already_exists) {
+ Copier cop = copier_create(tr->allocr, tr->block);
+ copy_struct(&cop, &inst->struc, base->struc);
+ size_t i = 0;
+ arr_foreach(inst->struc.params, Declaration, param) {
+ param->flags |= DECL_FOUND_VAL;
+ if (arr_len(param->idents) == 1) {
+ param->val = arg_vals[i];
+ ++i;
+ } else {
+ assert(param->type.kind == TYPE_TUPLE);
+ size_t nmembers = arr_len(param->type.tuple);
+ param->val.tuple = typer_malloc(tr, nmembers * sizeof *param->val.tuple);
+ for (size_t idx = 0; idx < nmembers; ++idx) {
+ param->val.tuple[idx] = arg_vals[i];
+ ++i;
+ }
+ }
+ }
+ assert(i == nparams);
+ Type struct_t = {0};
+ struct_t.kind = TYPE_STRUCT;
+ struct_t.struc = &inst->struc;
+ if (!type_resolve(tr, &struct_t, e->where)) /* resolve the struct */
+ return false;
+ inst->struc.instance_id = table->n;
+ }
+ /* expression is actually a type */
+ e->kind = EXPR_TYPE;
+ memset(&e->typeval, 0, sizeof e->typeval);
+ e->typeval.kind = TYPE_STRUCT;
+ e->typeval.flags = TYPE_IS_RESOLVED;
+ e->typeval.struc = &inst->struc;
+ t->kind = TYPE_BUILTIN;
+ t->builtin = BUILTIN_TYPE;
+ arr_clear(&arg_types);
free(params_set);
- return true;
+ goto ret;
}
fn_decl = val.fn;
@@ -2308,6 +2353,7 @@ static bool types_expr(Typer *tr, Expression *e) {
assert(0);
return false;
}
+ ret:
t->flags |= TYPE_IS_RESOLVED;
return true;
}
diff --git a/types.h b/types.h
index c9e1197..e20f03a 100644
--- a/types.h
+++ b/types.h
@@ -448,18 +448,41 @@ typedef struct Field {
size_t offset; /* offset during compile time */
} Field;
+
+enum {
+ BLOCK_IS_FN = 0x01,
+ BLOCK_IS_NMS = 0x02,
+ BLOCK_FINDING_TYPES = 0x04,
+ BLOCK_FOUND_TYPES = 0x08
+};
+typedef U8 BlockFlags;
+typedef struct Block {
+ BlockFlags flags;
+ Location where;
+ Identifiers idents;
+ struct Statement *stmts;
+ struct Expression *ret_expr; /* the return expression of this block, e.g. {foo(); 3} => 3 NULL for no expression. */
+} Block;
+
enum {
STRUCT_DEF_FOUND_OFFSETS = 0x01,
STRUCT_DEF_CGEN_DECLARED = 0x02,
- STRUCT_DEF_CGEN_DEFINED = 0x04
+ STRUCT_DEF_CGEN_DEFINED = 0x04,
+ STRUCT_DEF_RESOLVED = 0x08
};
-
typedef struct StructDef {
Field *fields;
Location where;
U8 flags;
- size_t size; /* size of this struct during compile time */
- size_t align;
+ Block scope; /* to make sure that parameters live somewhere. fields are not kept here. */
+ union {
+ HashTable instances;
+ struct {
+ size_t size; /* size of this struct during compile time */
+ size_t align;
+ U64 instance_id; /* ID of instance */
+ };
+ };
Identifier name;
struct Declaration *params;
struct {
@@ -469,21 +492,6 @@ typedef struct StructDef {
} StructDef;
-enum {
- BLOCK_IS_FN = 0x01,
- BLOCK_IS_NMS = 0x02,
- BLOCK_FINDING_TYPES = 0x04,
- BLOCK_FOUND_TYPES = 0x08
-};
-typedef U8 BlockFlags;
-typedef struct Block {
- BlockFlags flags;
- Location where;
- Identifiers idents;
- struct Statement *stmts;
- struct Expression *ret_expr; /* the return expression of this block, e.g. {foo(); 3} => 3 NULL for no expression. */
-} Block;
-
typedef enum {
EXPR_LITERAL_FLOAT,
EXPR_LITERAL_INT,
@@ -628,11 +636,14 @@ typedef struct FnExpr {
typedef struct Instance {
Value val; /* key into hash table */
- struct {
- FnExpr *fn; /* the typed function */
+ union {
struct {
- U64 id;
- } c;
+ FnExpr *fn; /* the typed function */
+ struct {
+ U64 id;
+ } c;
+ };
+ StructDef struc;
};
} Instance;